Открытый исходный код. Скрипт предназначен исключительно для управления локальными инстансами MuMu Emulator на вашем компьютере. Функции подмены устройства (IMEI/Android ID/MAC) предназначены для приватности и тестирования приложений на собственных инстансах. Полное объяснение — в разделе «Примечание для AV-аналитиков» ниже.
Интерактивное PowerShell-меню для управления MuMu Emulator 6.x
Языки: Русский · English summary
- 🚀 Запуск, выключение, перезагрузка эмулятора
- 🐑 Клонирование инстансов
- 🗑️ Удаление инстансов
- ✏️ Переименование инстансов
- 📦 Установка и удаление приложений (APK)
- 📱 ADB-команды
- 🧹 Очистка данных приложения, force stop, запуск приложения
- 💾 Экспорт данных инстанса (.mumudata)
- 💾 Резервное копирование папки данных инстанса (vms) с прогрессом
- 🗜️ Сжатие бэкапа в ZIP (встроенный tar, опционально с удалением исходной папки)
- 🎭 Подмена модели устройства (brand / model / код модели)
- 📶 Смена оператора/SIM страны (MCC/MNC, iso-country) — для TikTok и др. (38 пресетов + кастом)
- 🎲 Генерация случайных IMEI (с контрольной суммой) / Android ID / MAC
- 📸 Скриншоты эмулятора через ADB
- 🎬 Запись экрана (screenrecord, до 180с)
- 📁 Передача файлов push/pull между PC и эмулятором
- 💻 Интерактивная ADB-сессия (прямой shell)
- 🔐 Цифровая подпись скрипта (self-signed CodeSigning сертификат)
- 🪟 Управление окнами (показать/скрыть/расположить)
- 🔄 Массовые операции (все инстансы)
- 📋 Просмотр логов (статические файлы + adb logcat: снапшот, live-стрим, фильтр по уровню/тегу)
- 🛡️ Менеджер GitHub-токена (DPAPI-шифрование)
- 📊 Информация о версиях
- ⚡ Автообновление из GitHub
- 🗄️ Загрузка репозитория (git clone, ZIP, отдельный файл)
- Windows 10/11
- PowerShell 5.1+ или PowerShell 7+
- MuMu Emulator 6.x — актуальная линейка, протестировано на V6.7.1 (минимальная поддерживаемая версия: 4.0.0.3179)
git clone https://github.com/genrihx2/MuMuManager-CLI-Menu.git
cd MuMuManager-CLI-Menu
.\mumu-menu.ps1- Скачайте
mumu-menu.ps1 - Поместите в любую папку
- Запустите
.\mumu-menu.ps1
Опционально: чтобы открывать меню командой mumu, вставьте сниппет в свой PowerShell-профиль (notepad $PROFILE):
function mumu { & "C:\путь\к\mumu-menu.ps1" }Скачайте актуальный zip со страницы Releases, распакуйте и запустите mumu-menu.ps1.
Как работают релизы:
- Релизы создаются автоматически (GitHub Actions) из тегов
v*: пуш тега или[CR]в меню — ZIP всегда собирается из содержимого тега - Релиз не публикуется, если
$scriptVerвmumu-menu.ps1не совпадает с версией тега - Каждый релиз привязан к тегу (например
v1.19.0) — обновления берутся только из тегов - ZIP-архив содержит:
mumu-menu.ps1,bootstrap-update.ps1,README.md,SKILL.md,.version - После публикации релиз автоматически сканируется на VirusTotal (ZIP +
mumu-menu.ps1+SKILL.md), а вердикты с пермалинками публикуются в описании релиза - Теги нельзя удалить/перезаписать — это гарантирует целостность истории обновлений
- Релизы с проверяемыми SHA-256 ассетами начинаются с v1.18.6; более старые v1.18.1–v1.18.5 и v1.2.1–v1.2.5 остались тегами без релизов (чистка пустых релизов 2026-09-16, теги сохранены)
Способы установки:
- Быстрый запуск (одна команда — скачивает и запускает):
irm https://raw.githubusercontent.com/genrihx2/MuMuManager-CLI-Menu/main/mumu-menu.ps1 -OutFile $env:TEMP\mumu-menu.ps1; & $env:TEMP\mumu-menu.ps1- Git clone (с возможностью обновления через
[U]):
git clone https://github.com/genrihx2/MuMuManager-CLI-Menu.git
cd MuMuManager-CLI-Menu
.\mumu-menu.ps1-
Скачать ZIP вручную со страницы Releases, распаковать и запустить
mumu-menu.ps1. -
CDN-зеркало jsDelivr (если браузер или провайдер блокирует raw-ссылки):
curl.exe -sSL -o $env:TEMP\mumu-menu.ps1 https://cdn.jsdelivr.net/gh/genrihx2/MuMuManager-CLI-Menu@v1.22.15/mumu-menu.ps1; & $env:TEMP\mumu-menu.ps1Браузер предупреждает «mumu-menu.ps1 может навредить вашему устройству»? Это срабатывание по типу файла (
.ps1= исполняемый скрипт PowerShell), а не по содержимому: URL-сканеры и Safe Browsing не анализируют скрипты, но блокируют скачивание исполняемых типов по шаблону. Файл чист — все релизы проходят CI-скан VirusTotal (вердикты в теле каждого релиза, см. «URL-репутация» ниже). Скачивайте из официального релиза или через jsDelivr, сверяйте SHA-256 ([F]после установки), не берите скрипт из сторонних ссылок.
.\mumu-menu.ps1======================================
MuMuManager CLI Menu
======================================
--- Emulator Control ---
[1] Show emulator info
[2] Launch emulator
[3] Shutdown emulator
[4] Restart emulator
[5] Create new emulator (Android 12/15)
[C] Clone emulator
[X] Delete emulator
[N] Rename emulator
--- Apps and Settings ---
[6] List installed apps
[7] Show settings
[RT] Enable / disable root (instance)
[VE] Virtual environment (enable/disable/remove)
[FPS] Set frame rate (30/60/90/120/144/240/uncapped)
[8] Install APK
[9] Uninstall app
[G] View logs
--- Batch ---
[B] Launch all instances
[D] Shutdown all instances
[R] Restart all instances
[I] Install APK to all
--- Window ---
[W] Show all windows
[H] Hide all windows
[L] Layout windows
--- Tools ---
[S] Take screenshot
[A] Run ADB command
[AF] ADB file transfer (push/pull/list)
[AS] ADB screen capture (screenshot/record)
[AH] ADB interactive shell
[O] Clear app data
[P] Force stop app
[T] Start app
[E] Export emulator data
[BA] Backup instance data
[RE] Restore from backup
[K] Update GitHub token
[VK] Set VirusTotal API key
[CRT] Create/sign certificate
[Z] Security audit (disabled)
--- Tests ---
[TC] Connection test
[TN] Network test
[TS] Network speed test
[TD] Dependencies test
[VT] VirusTotal scan
[VF] VirusTotal Upload file
[UW] Fix Unicode / encoding
--- Spoofing ---
[DM] Spoof device model
[SIM] Change SIM operator / country (MCC/MNC)
[SIM+] View / clear auto-apply SIM config
[SC] SIM check (all properties)
[AI] Set Android ID
[DI] Random device IDs
--- Info ---
[WN] Watch MuMu network + updater
[V] Version info
[U] Check for updates
[UP] Update plan (dry-run)
[F] Verify installation (files vs release tag)
[ST] Install status (read-only)
[J] Update journal
[DIAG] Problem diagnostics
[RB] Rollback from backup
[DL] Download repository
[CR] Create release
[FR] Fix release encoding
[0] Exit
======================================
Select option: 2
Select instance to launch (0-9): 0
Launching instance 0...
[#-----------------------------] 2% [ 3s] state: starting_vm
[##----------------------------] 5% [ 6s] state: starting_rom
[##############################] 100% Emulator is running! (booted in ~20s)
Select option: B
Found 3 instance(s)
[0] Android Device - launching...
[1] Game Phone - launching...
[2] Test Device - launching...
All instances launched. Polling boot status...
[5 s] still booting...
[10 s] still booting...
All instances ready in ~15s!
Select option: I
Enter APK file path: C:\Downloads\game.apk
Installing game.apk (45.2 MB) to 3 instance(s)...
[0] Android Device - installing...
[0] Android Device - OK
[1] Game Phone - installing...
[1] Game Phone - OK
[2] Test Device - skipped (not running)
Done! Success: 2, Failed: 0
Select option: C
Select instance to clone (0-9): 0
Cloning instance 0...
Source: [0] Android Device
Clone completed!
Current instances:
[0] Android Device - start_finished <-- source
[1] Android Device (1) - stopped
Select option: X
Select instance to DELETE (0-9): 1
WARNING: This will permanently delete instance 1!
Type YES to confirm: YES
Deleting instance 1...
Instance deleted!
Select option: N
Select instance to rename (0-9): 0
Current name: Android Device
Enter new name: My Phone
Renaming to 'My Phone'...
Renamed to 'My Phone'!
Select option: L
Arranging emulator windows...
Done! Windows arranged.
Select option: DM
Select instance: 0
Current device model:
Brand: Samsung
Model: Galaxy A54
Code: SM-A546E
Device presets:
[ 1] Samsung Galaxy S23 Ultra (SM-S918B)
[ 2] Samsung Galaxy A54 (SM-A546E)
[ 3] Google Pixel 8 Pro (G1MNW)
...
Select device: 3
Setting device to Google Pixel 8 Pro (G1MNW)...
Device model set to Google Pixel 8 Pro!
Device name updated live.
Restart the emulator to fully apply build properties.
Select option: DI
Select instance: 0
Current simulated properties:
IMEI: 353240116262762
Android ID: (not set)
MAC: (not set)
Randomize:
[1] IMEI
[2] Android ID
[3] MAC address
[4] All of the above
Select option: 4
IMEI -> 356821728580688
Android ID -> 13f454f21c0f5f57
MAC -> e2:fa:65:e3:f5:38
Done! Restart the emulator to apply.
Select option: S
Select instance (0-9): 0
Taking screenshot of instance 0...
Screenshot saved: screenshots\screenshot_0_20260821_153000.png
Size: 1614.1 KB
Select option: V
=== MuMu Manager CLI Menu ===
Script version: 1.22.54
MuMu version: 6.7.1
PowerShell: 5.1.28000.2704
OS: Windows 10.0
Repository: genrihx2/MuMuManager-CLI-Menu
GitHub token: configured
Instances: 1 (1 running)
По умолчанию скрипт ищет:
C:\Program Files\Netease\MuMuPlayer\nx_main\MuMuManager.exe
Если MuMu установлен в другое место, измените переменную $MumuPath в начале файла mumu-menu.ps1.
При запуске скрипт выполняет быструю проверку версии через GitHub API (сравнение тегов без скачивания файлов) — на старте ничего не скачивается.
Загрузка файлов возможна исключительно вручную: пункт меню [U] Check for updates + подтверждение. При этом:
- Быстрый путь: сравнение локального
.versionс тегом релиза (мгновенно, без скачивания) - Медленный путь: при различии тегов скачивание файлов для сравнения хешей (устойчиво к разнице CRLF/LF)
- Обновления берутся только из тегов GitHub Releases, а не из ветки
main - Показывается changelog (до 20 строк) перед подтверждением
- Прогресс загрузки с отображением скорости и размера (
curl.exe -#) - Перед перезаписью предыдущие версии сохраняются в
backup\<дата_время>\(авто-очистка старше 5) - Таймауты и повторы всех сетевых запросов (через встроенный
curl.exe)
Для приватных репозиториев сохраните токен через пункт меню [K] Update GitHub token — он проверяется и хранится зашифрованным через Windows DPAPI в .github-token.dpapi; плейнтекстовый .github-token мигрирует в зашифрованное хранилище автоматически при первом запуске.
[F] Verify installation сверяет локальные файлы с содержимым текущего тега релиза по SHA-256:
- Отчёт по каждому файлу:
OK/DRIFT(с обоими хешами) /MISSING/N/A - Маркер
.versionсравнивается семантически: локальный маркер, равный или более новый, чем отстающий маркер тега (бот синхронизации версий приземляется после тега), не является дрейфом - Один повторный запрос перед вердиктом DRIFT: CDN-граница GitHub может отдать устаревший блоб минуты после пуша тега — настоящий дрейф остаётся дрейфом, случайная устаревшая копия прощается (
rechecked - first read was stale) - Ошибки API (rate limit) никогда не принимаются за содержимое — файл честно помечается
N/A, итог «partial» вместо ложного дрейфа
Проверка релизного ZIP до распаковки ([F] предложит после проверки, или bootstrap-update.ps1 -VerifyZip <файл.zip>):
- SHA-256 ZIP против
.sha256-сайдкара, точный набор из 8 файлов,$scriptVerиз архива против тега (набор файла-сета расширен 5 → 8 в v1.22.46 — см. «Что нового») - Вердикт:
OK - safe to installилиFAILED - do not install from this archive; отсутствующий архив — это «nothing to verify», а не FAILED - Все события пишутся в журнал
[J](zip-verify-ok/zip-verify-fail)
Оба обновлятора ([U] и bootstrap-update.ps1) дополнительно сверяют каждый скачанный файл с ожидаемым SHA-256 из содержимого тега; при расхождении обновление останавливается до записи .version.
Принцип: не верить ни «всё ок», ни «всё сломано» на слово — сначала диагностика, потом действие. Диагностика: [ST] (сводный статус), [DIAG] (проблемы установки), [F] (полная сверка файлов с тегом релиза), [J] → 3 (ошибки в журнале).
Обновлятор остановился до записи .version, журнал содержит update-fail.
- Запустите
[F]— сверка локальных файлов с тегом релиза покажет, какой именно файл отличается и в какую сторону. - Один разовый ложный HASH MISMATCH бывает при stale-CDN чтении эталона (лечится повторным прогоном
[F]: проверка делает re-fetch, аDRIFT/MISMATCHисчезает — значит, сеть соврала, не файл). - Стабильный MISMATCH = реальное расхождение. Не устанавливайте ничего из подозрительного архива; скачайте ZIP из релиза заново и проверьте через
bootstrap-update.ps1 -VerifyZip <файл>.
.version показывает новую версию, но $scriptVer в меню — старый. Это был баг лечения v1.20.5-эры; с v1.20.5 + пином тега (#22) причина невозможна, но распознать стоит: [DIAG] прямо называет это «marker AHEAD of content - wedged heal».
Лечение: powershell -ExecutionPolicy Bypass -File bootstrap-update.ps1 -Force — принудительно скачивает контент последнего тега и выравнивает маркер.
- Найдите последнюю папку
backup\YYYYMMDD_HHMMSS— bootstrap копирует туда все 4 файла перед заменой. - Скопируйте файлы из бэкапа обратно в каталог установки.
- Запустите
[F]и убедитесь, что установка снова совпадает с тегом.
Обновлятор увидел чужой .update-lock — параллельный [U] или bootstrap. Сообщение содержит PID держателя и возраст блокировки.
- Если обновление действительно идёт в другом окне — просто подождите.
- Если держатель давно мёртв — блокировка старше 10 минут сломается автоматически при следующем обновлении; ждать не нужно.
- Отказ фиксируется в журнале как
update-skipped(виден в[J], подсвечен жёлтым — это не ошибка).
| Симптом | Причина | Действие |
|---|---|---|
HASH MISMATCH при обновлении |
Stale-CDN эталон или реальное расхождение | Повторить [F]; стабильно — скачать ZIP заново + -VerifyZip |
| «Up to date», но контент старый | Клин маркера (устаревший класс бага) | bootstrap-update.ps1 -Force; проверить [DIAG] |
| Меню не стартует после обновления | Битые файлы | Восстановить из backup\YYYYMMDD_HHMMSS, затем [F] |
Another update is already running |
Чужой активный обновлятор | Ждать; stale-лок сломается сам через 10 минут |
zip: FAILED - do not install |
ZIP не совпал с .sha256 или составом |
Не устанавливать; скачать ZIP из релиза заново |
zip: No ZIP found at … |
Просто нет файла по пути | Ничего — это «nothing to verify», не ошибка |
DRIFT в [F] без сетевых проблем |
Локальные файлы изменены | Сравнить изменения, затем bootstrap для выравнивания |
| «not digitally signed» на файлах из ручного ZIP | Mark-of-the-Web (Zone.Identifier) от браузера | Секция «MotW» ниже: Unblock-File, [U]/bootstrap или распаковка не-Проводником |
Подробности: [F] и -VerifyZip — раздел «Проверка целостности» выше; журнал и экспорт — [J]; сводный статус — [ST].
EN summary: Recovering from a failed update: diagnose first ([ST] status, [DIAG] problems, [F] file-vs-tag verification, [J] → 3 errors), then act. HASH MISMATCH → re-run [F] (stale-CDN false alarms vanish on the re-fetch; stable mismatches mean re-download the ZIP and verify with -VerifyZip). Wedged marker ("Up to date" but old content) → bootstrap-update.ps1 -Force. Broken files → restore from backup\YYYYMMDD_HHMMSS. Lock refusal → wait (locks older than 10 minutes break automatically). The table above maps each symptom to its cause and fix.
Симптом: после скачивания релизного ZIP браузером и распаковки Проводником PowerShell отказывается запускать скрипты:
File C:\...\mumu-menu.ps1 cannot be loaded. The file ... is not digitally signed.
You cannot run this script on the current system.
Почему так: браузер помечает скачанный файл потоком NTFS Zone.Identifier (Mark-of-the-Web, MotW). Проводник при распаковке копирует эту метку на каждый извлечённый файл. Политика выполнения RemoteSigned требует подписи для всех «пришедших из интернета» файлов — и блокирует их, даже если содержимое корректно. Подписи Authenticode в ZIP нет: релизный архив собирается CI из тега (git archive), а подпись на файлы ставит только установщик (bootstrap) уже на инсталляции. MotW — чисто локальный механизм доверия Windows: он не связан с содержимым (которое побайтно сверено с тегом в CI), и его снятие безопасно.
Проверить метку можно так (пустой вывод — метки нет):
Get-Item .\mumu-menu.ps1 -Stream Zone.Identifier -ErrorAction SilentlyContinueТри способа лечения — от рекомендуемого к разовому:
-
Меню
[U]илиbootstrap-update.ps1(рекомендуется). Не распаковывайте ZIP вручную вообще: апдейтер проекта скачивает файлы по HTTPS из релиза, сам снимает метки и подписывает скрипты сертификатом проекта. Установка одной строкой из раздела «Установка» использует тот же bootstrap — после неё всё запускается сразу. -
Unblock-File— снять метку с уже распакованных файлов:Get-ChildItem 'C:\путь\к\MuMuManager-CLI-Menu' -Recurse -File | Unblock-File
Это ровно то, что нужно: метка удаляется, содержимое не меняется, подпись не требуется при
RemoteSigned. -
Распаковывать не Проводником. Метку наследует именно встроенный экстрактор Проводника;
tar -xf MuMuManager-CLI-Menu-v1.22.48.zip(встроен в Windows 10+) или 7-Zip распаковывают безZone.Identifier— файлы сразу запускаются.
EN summary: Manual ZIP extraction via Windows Explorer propagates Mark-of-the-Web (NTFS Zone.Identifier) to every file, and RemoteSigned then blocks unsigned "internet" files. Fix: prefer [U]/bootstrap (they download, unblock and sign automatically); or Get-ChildItem <dir> -Recurse -File | Unblock-File; or extract with tar -xf/7-Zip, which do not propagate the mark. MotW is a local trust mechanism only — release content is CI-verified byte-for-byte against the tag.
- Test-MumuTunnelAB: определение владельца Wintun-туннеля (read-only) — каждый снапшот находит Up-адаптер
*Wintun*, резолвит владельцев портов прокси-ядер (SOCKS 10808/10809, mihomo 7890–7893), поднимается по цепочке родителей и пишет путь + командную строку; если владелец неMuMu*— предупреждение «тумблер MuMu на этот адаптер не влияет» (полевой случай: системный туннель оказался прокси INCY, порт 10808). Новый ключ-NoOwnerLookup— быстрый режим без поиска владельца. Как и раньше, ничего не убивается и не меняется. - Version bump:
$scriptVerinmumu-menu.ps1,relnotes.md,README.mdand.versionsynchronized to1.22.54.
EN summary: Test-MumuTunnelAB snapshots now identify the Wintun tunnel owner (read-only): resolve proxy-core port listeners (SOCKS 10808/10809, mihomo 7890-7893), walk parent chains, record path + command line; warn when the owner is not a MuMu* process (field case: the system tunnel belonged to INCY on port 10808, not MuMu). New -NoOwnerLookup switch skips the probe. Still read-only — nothing killed, nothing changed.
- [V] startup/version block now lists the active install only -
Show-MumuExeVersionsresolves the directory containing theMuMuManager.exethe startup check resolved and skips any parallel second install (e.g. a leftoverNetease1\MuMu), so the startup block prints a single install'sMuMuPlayer.exe/MuMuNxMain.exe/MuMuNxUpdater.exeversions with the auto-read version and a build-date stamp (full discovery viaGet-MumuInstallRootsremains the fallback whenMuMuManageritself was not found). - Version bump:
$scriptVerinmumu-menu.ps1,relnotes.md,README.mdand.versionsynchronized to1.22.53.
- Фикс запуска под строгим pwsh-хостом — при
Set-StrictMode -Version Latestиз$PROFILEзапуск падал на ленивом чтении сессионных таблиц ETag-кэша («cannot be retrieved because it has not been set» → «Could not check MuMu version»); таблицы декларируются сразу, плюс strict-safe чтениеDisplayNameв реестровом обходе. - Блок версий EXE — только активная установка — строки параллельной второй инсталляции (например,
Netease1\MuMu) больше не дублируются; полное обнаружение осталось как fallback. - CI: пост-публикационный guard-аудит — release.yml диспетчеризует release-guard сразу после publish.
EN summary: Strict-host startup fix (session tables declared up front; strict-safe DisplayName read in the registry walk — no more "Could not check MuMu version" under Set-StrictMode hosts). The EXE version block lists the active install only (no duplicate parallel-install lines). release.yml dispatches the release-guard audit right after publishing.
- Поиск корней MuMu на любом диске —
Get-MumuInstallRootsобнаруживает установку автоматически: каталог MuMuManager, живые процессыMuMu*, реестровые Uninstall-записи, ярлыки «Пуска»; при пустых быстрых источниках — ограниченный спул по всем фиксированным дискам (папки*Netease*/*MuMu*, ≤3 уровней, признакnx_main/целевой EXE). Жёстко прописанные C-пути больше не используются. - [V] — реальные полные пути — блок «MuMu EXE versions» печатает обнаруженный путь каждого бинарника с авто-версией (каскад
FileVersion→ProductVersion→ версия продукта →unknown) и штампом сборки; ссылка на официальные release notes — на месте.
EN summary: MuMu install roots are now discovered on any drive (MuMuManager dir, live processes, registry uninstall entries, Start Menu shortcuts; bounded fixed-drive sweep over Netease/MuMu folders as fallback) — no hard-coded C: paths. [V] prints the discovered full path per binary with the auto-read version and build stamp, plus the official release-notes link.
- Автоверсии MuMu-EXE при запуске — меню автоматически находит
MuMuPlayer.exe/MuMuNxMain.exeиMuMuNxUpdater.exe(каталог MuMuManager, обе известные установки, пути живых процессов) и печатает версию каждого файла со штампом сборки. У MuMu 6.x эти EXE не несут ресурса версии — каскад:FileVersion→ProductVersion→ версия продукта изMuMuManager version(с пометкой) →unknown. Ручной ввод исключён.
EN summary: Startup now auto-detects and prints MuMuPlayer/MuMuNxUpdater EXE versions (discovery via MuMuManager dir, both known install roots, live process paths; resolution: version resource → ProductVersion → MuMuManager product version → unknown, always with a build-date stamp). No manual input.
- README: раздел про Mark-of-the-Web — почему ручная распаковка ZIP Проводником блокирует скрипты (
not digitally signed) и три способа лечения:[U]/bootstrap (сами скачивают, снимают метки и подписывают),Unblock-File, распаковкаtar -xf/7-Zip. Плюс строка-симптом в таблицу восстановления. - CI: CodeQL Advanced — анализ файлов воркфлоу (язык
actions), пины по SHA, weekly-расписание;.ps1-код остаётся под DevSkim + PSScriptAnalyzer. - Харденинг Test-ReleaseZip — повреждённый ZIP больше не роняет
[F]/-VerifyZipисключением: любое повреждение архива даётarchive: corrupt (...)иOk=$false; новый Pester-тест фиксирует контракт «никогда не бросает», tampered-тест стал детерминированным.
EN summary: Docs-only release: README gains a Mark-of-the-Web section (why Explorer-extracted ZIP files are blocked and the three fixes: [U]/bootstrap, Unblock-File, tar/7-Zip extraction). CI adds CodeQL Advanced over workflow files. Test-ReleaseZip hardened in both updaters to never throw on corrupt archives (Ok=$false with an "archive: corrupt" check line; new never-throws Pester test, deterministic tamper fixture).
- Фикс self-update: [U] снова доставляет полный комплект — список загрузки в
Update-FromGitHubостался на до-троичном составе из 4 файлов (v1.22.46 расширила ZIP до 8, но[U]— нет), поэтому файлы, добавленные после v1.22.45, не доходили до существующих инсталляций через[U]. Список приведён к контракту 8 файлов; дефолты rollback-функций (Build-RollbackPlan/Invoke-Rollback) расширены до того же сета — валидация бэкапов честно перечисляет недостающие файлы старых бэкапов. Новый Pester-тест фиксирует список[U]на контракте. - [WN] Watch MuMu network + updater — новый read-only пункт меню (секция Info): каждые 5 с логирует НОВЫЕ внешние TCP :443 подключения MuMu*-процессов, запуски MuMuNxUpdater (время, PID, имя), смену EXE-идентичности апдейтера (FileVersion / ProductVersion / LastWriteTime / полный путь) и его удалённые IP во время обновления; дедуп по PID+локальный порт+удалённый кортеж; лог
C:\test\mumu-network-update.txt; выход по Q/Ctrl+C. Ничего не меняет: ни firewall, ни прокси, ни DNS, ни маршруты. - Фикс Diag-MumuNx (uint32) — разделы «Listening endpoints / TCP connections / UDP endpoints» были пустыми при работающем MuMu: ключи
$procRows—[int]PID,OwningProcess—[uint32], хэш-таблица молча не совпадала по типу ключа. Подтверждено живым elevated-снимком (11 слушателей, ADB — только loopback). - Дружелюбный pre-flight в Diag-MumuNx — вместо жёсткого
#requires -RunAsAdministrator(не поймать) — runtime-проверка с готовой командой запуска от администратора.
EN summary: [U] self-update downloads the full 8-file deployed set again (the list was stuck on the pre-trio 4 files), rollback defaults widened to match, new contract test pins the list. New read-only menu entry [WN]: MuMu network + updater watcher (new external :443 connections, updater launches/EXE versions/remote IPs, PID+port dedup, Q/Ctrl+C to stop). Diag-MumuNx uint32 key-type fix (socket sections were silently empty while MuMu ran) and a friendly elevation pre-flight.
- Version bump:
$scriptVerinmumu-menu.ps1,.version, README and relnotes synchronized to1.22.47. - No code changes: this release only synchronizes the version markers after v1.22.46.
- Диагностическая троица в комплекте — release ZIP теперь несёт 8 файлов: добавлены read-only инструменты сетевой диагностики MuMu.
Watch-MumuConnections.ps1— опрос TCP-таблицы раз в 5 с, в лог только НОВЫЕ установленные подключения MuMu*-процессов (дедуп по 5-tuple+PID — кто, куда и когда, без дублей по долгоживущим сессиям).Test-MumuTunnelAB.ps1— снимки сети A/B с diff: подключения, source-адреса, default/fake-IP маршруты, route-lookup по каждому адресату, адаптеры, прокси; режим-Watchсам ловит исчезновение/появление198.18.*(переключение туннеля) и снимает B + отчёт без ручного вызова.Diag-MumuNx.ps1— запуск от администратора: сервисы и процессы MuMu с командными строками, слушатели, TCP/UDP с DNS-резолвингом адресатов, firewall-правила MuMu → логMuMuNx-*.txt. Ни один скрипт не меняет VPN, маршрутизацию или прокси. - Контракт файла-сета: 5 → 8 файлов — синхронно обновлены:
Test-ReleaseZipв обоих апдейтерах (строгая проверка missing/extras), списки самобновления[U]и bootstrap-update (новые файлы доставляются на существующие инсталляции), fixture deployed-layout ноги CI (tests/test-deployed-layout.ps1), недельный zipcheck в release-guard (EXPECTED_COUNT=8), T7/T8 тесты (stub-фикстуры и «file set: OK (8 files)»). Старые инсталляции (список из 5) по-прежнему обновляются без ошибок: их списки — подмножество. - Проверено на живой системе: вотчер поймал «Network error»-фон MuMuPlayer 6.8.0 — циклический рестарт MuMuNxUpdater (новый PID каждые 30–60 с), fake-IP туннель (198.18.0.1, Wintun, default route) и периодические 10-секундные ступоры HTTPS до
api.mumuglobal.comпри полностью живом хосте; elevated-снимок выявил две параллельные инсталляции MuMu (Netease\MuMuPlayer+Netease1\MuMu) и отсутствиеMuMuNxService.exe(реальные сервисы:MuMuPlayerRemoteService,MuMuRemoteService).
EN summary: Diagnostics trio ships in the ZIP: Watch-MumuConnections.ps1 (dedup log of NEW MuMu TCP connections), Test-MumuTunnelAB.ps1 (A/B network snapshots with diff + -Watch auto-trigger on fake-IP route change), Diag-MumuNx.ps1 (elevated read-only services/processes/connections/firewall snapshot). Release file-set contract widened 5 → 8 files; Test-ReleaseZip, [U]/bootstrap file lists, CI deployed fixture, release-guard zipcheck and T7/T8 tests updated in lockstep.
- CI: deployed-layout Pester leg — the suite runs inside a fixture holding only the deployed file set (mumu-menu.ps1, bootstrap-update.ps1, README.md, SKILL.md, .version); repo-only files excluded (relnotes.md, RELEASE-RUNBOOK.md, update-readme.ps1, tests/). Tests tagged RepoFiles are excluded (172 of 173); both engines — PowerShell 5.1 and pwsh 7 — against the SAME copy (tests/test-deployed-layout.ps1). CI job pester-unit (deployed layout / both engines); composite action gets a layout input (repo|deployed); run-matrix.ps1 replays the leg locally.
- CI: release gate audits every Tests leg by exact name — dropping or renaming a leg from the matrix now blocks a release ("missing" instead of silently shrinking coverage). Last-row-wins re-run semantics kept (green→red blocks).
- PSSA: присваивание сплат-переменной
$argsвtests/test-deployed-layout.ps1переименовано в$exeArgs(PSAvoidAssignmentToAutomaticVariable, code-scanning #590/#591) — поведение идентично - SKILL.md: задокументирована deployed-layout нога — дерево
tests/(test-deployed-layout.ps1, тегRepoFilesв сьюте), состав матрицыtests.ymlи локальный прогон черезtests/run-matrix.ps1/tests/test-deployed-layout.ps1
- «Token rejected — retrying without auth...» на каждый запрос: отклонённый GitHub'ом сохранённый токен оставался активным до конца сессии — каждый запрос заново проходил цикл «с токеном → 401 → повтор без авторизации». Теперь токен отключается один раз на уровне script-scope с подсказкой «re-save via menu [K]», дальше всё анонимно (репозиторий публичный); централизованный guard добавлен и в
Invoke-GitHubApiGet(releases/branches/tags/compare раньше не различали Bad credentials вовсе), и в bootstrap — где прежний сброс был переменной-тенью и не работал
- Release-гейт стал самодостаточным: перед публикацией релиза workflow сам запускает Tests-матрицу на SHA тега — переиспользует уже идущий run, иначе диспетчеризует
tests.ymlпо--ref <тег>и ждёт до 25 минут; после зелёного рана — аудит ног (bootstrap-detector+ всеpester-unit), fail-closed на red/missing/timeout - Еженедельная ZIP-проверка в release-guard: ZIP последнего релиза скачивается,
.sha256-sidecar проверяется, SHA256 каждого из 5 файлов сверяется сgit show <tag>:<file>— ловит подмену/обрезку/недозагрузку ассета даже после публикации; violations — в тот же marker-scoped issue - Фикс гейта — якорный regex отсекал ноги матрицы (найдено репетицией на живом теге): фильтр
^(bootstrap-detector|pester-unit)$не совпадал с именами видаpester-unit (5.7.1 / powershell)— гейт блокировал бы каждый релиз; заменено на префиксное совпадение - Фикс дедупликации чек-ранов: прежний
sort -uоставлял алфавитно-первую строку (failure) — тег после зелёного re-run блокировался бы ложно; теперь берётся последняя строка на имя
- CI-матрица Pester:
pester-unitвtests.ymlтеперь гоняет сьют на ОБОИХ движках — Windows PowerShell 5.1 и pwsh 7 — на закреплённом Pester 5.7.1 через композитный экшен.github/actions/pester-unit, плюс «канареечная» нога на предустановленном в раннере Pester (сегодня 6.x), которая ловит дрейф движка/Pester заранее, а не по репорту пользователя - Фикс из матрицы —
Get-ReleaseInfo.PublishedAt: PS 5.1ConvertFrom-Jsonоставляет ISO-даты строками, pwsh 7 конвертирует в[datetime]— свойство было движко-зависимым; явный каст[datetime]закрепил контракт для обоих движков (на 5.1 это был бы сырой string). Матрица поймала это на первом же прогоне: 1 тест из 170 красный на 5.1, зелёный на 7 - Раннер
tests/run-pester.ps1: новые параметры-PesterVersion/-ModuleDir(приватная копия Pester поверх PSModulePath) — CI и локальный прогон используют один и тот же скрипт; установка Pester движко-осведомлённая (PSResourceGet на Core, PowerShellGet + NuGet-провайдер на 5.1)
Get-ReleaseInfo— мёртвые заголовки:$headers(Accept/User-Agent/Authorization) собирались и игнорировались — транспортInvoke-GitHubGetпринимает только URL и таймаутUpdate-FromGitHub— сбои снова различимы: причина приходит изGet-ReleaseInfoчерез-Failure, и[U]/[UP]рендерят прежние сообщения (подсказки по rate limit, текст ошибки API, «No releases found on remote») вместо одной общей строки- Тесты: контракт
-Failureи запуск рендера по каждому виду сбоя; фикстура диагностики больше не показывает модальный диалог загрузчика Windows
- Меню [U]/[UP] — функция
Get-ReleaseInfo: структурированные данные последнего GitHub-релиза (тег,$scriptVerблоба, дата, автор, ассеты с URL) в одном переиспользуемом вызове; причина сбоя отдаётся вызывающему через-Failure(no-release/rate-limit/api/transport), поэтому[U]/[UP]рендерят прежние сообщения — подсказки по rate limit, текст ошибки API и сетевой сбой Update-FromGitHub— рефакторинг: инлайн-fetchreleases/latestзаменён наGet-ReleaseInfo, поведение обработки ошибок сохранено 1-в-1- CI/Dependabot: лейбл
dependenciesсоздан и указан корректно;upload-sarif→ v4.38.1 (per-language CodeQL bundles)
-
Меню [G] View logs: свёртка стек-логгера — голые фреймы
Name:Method(Type)и пустые продолжения того же тега скрываются, каждая ошибка печатается одной строкой, итог[stack] collapsed N stack line(s)(проверено на реальном логе: 24 строки → 6 сообщений) -
Документация: дата релиза v1.22.37 в README и relnotes приведена к фактическому
published_at(22.09.2026 — релиз пересёк полночь UTC)
- Меню [5] Create instance: исправлены вызовы
Write-Debug(PSSA: позиционные параметры → одна интерполированная строка)
- Меню [5] Create instance: панельный редизайн — рамка с версией Android, дифф-детекция нового инстанса (честный итог вместо слепого «Done!»), маркер
<-- newв списке
- Меню [G] View logs: поиск [6] — подстрока без учёта регистра, подсветка совпадений, несовпадающие строки приглушены, сводка с счётчиком
- Меню [G] View logs: snapshot-дефолт фильтра — errors-only (E) на пустой Enter; live сохраняет полный поток, дефолт показывается в промпте
- Меню [G] View logs: фильтр тишины [5] — скрывает известный шум (Play Store, vsync, GC, binder) в snapshot/live с счётчиком скрытых строк
- Меню [3] Shutdown и [4] Restart: панельный редизайн — guard «ALREADY STOPPED», верифицированный итог выключения, статус-линия по факту состояния, честный итог загрузки
- Меню [G] View logs: панельный редизайн — состояние инстанса, guard logcat на остановленном, раскраска logcat по уровню (E/W/D), открытие полного лога в notepad
- Меню [2] Launch emulator: новый экран в панельном стиле [RT]/[VE] — guard «ALREADY RUNNING», статус запуска, честный итог загрузки, вывод API с отступом
- CI: DevSkim security linter — SARIF-скан в Security tab (push/PR + еженедельно); DevSkim-Action пин v1.0.16
- Документация: SKILL.md обновлён — реальное дерево проекта, полное меню, 10 воркфлоу
- Фикс [TN]: hotfix шага [5] —
.tag_nameизвлекался вне$( ), в сравнение попадал весь объект релиза вместо тега (поймано живым прогоном); регрессионный тест на форму извлечения
- Улучшение [TN]: новый шаг [5] «CDN mirror freshness» (host-side) — сравнивает
.versionс зеркалаcdn.jsdelivr.net/@mainс тегом последнего релиза и выводит вердикт: Fresh (совпадают), STALE (зеркало отстало — подсказка пуржа), Main ahead (основная ветка впереди релиза — бамп в полёте), N/A (обе стороны недоступны) - CI: новый воркфлоу
cdn-sync— авто-пурж зеркала jsDelivr после каждого пуша в main, еженедельно и по запросу
- Документация: SmartScreen-инструкция по шагам для Chrome и Edge + раздел разблокировки MOTW (Свойства → «Разблокировать»,
Unblock-File, проверкаZone.Identifier)
- Улучшение [DIAG]: классификация stale fail-записей журнала — update-fail, перекрытый последующим успехом (update-ok / self-apply / zip-verify-ok), показывается как historical info с именем перекрывшего успеха вместо actionable warning
- Фикс [F]: ложный DRIFT на переподписанной установке — trailing Authenticode signature block теперь срезается перед хешированием (v1.22.24 regression)
- Обновление: установка v1.22.23 получала [VE]-фиксы и ephemeral token только из main после тега — релиз v1.22.24 закрепляет их в тегированном ZIP для [U]/[F]/bootstrap
- Новое [FPS]: быстрая смена FPS инстанса — пресеты (30/60/90/120/144/240) + кастомное значение + uncapped (999). Автоматический read-back и перезапуск для применения
- Улучшение [FPS]: обзор FPS всех инстансов перед выбором — таблица с ID, именем, текущим FPS и состоянием
- Улучшение [RT]: новый дизайн с рамкой, индикаторами ●/○, структурированным меню и progress-индикатором
- Фикс [VE]: исправлен regex для определения состояния пользователя — ADB отдаёт
UserInfo{10:test:1030}, а неUserInfo{10}. Добавлена пауза 2 сек перед проверкой после start/stop - Фикс [VE]: кириллица в именах пользователей (Владелец) теперь отображается корректно (UTF-8 encoding fix)
- Новое [K] [E]: ephemeral token — использование токена только для текущей сессии без сохранения на диск
- Фикс: trailing whitespace в 7 строках (PSScriptAnalyzer #548-#554)
- Новое [TS]: сетевой тест скорости — проверка подключения к GitHub API и CDN с замером задержки и пропускной способности; проверка rate limit剩余
- Улучшение [U]: экспоненциальная задержка retry при rate limit (2s → 4s → 8s), до 3 попыток
- Улучшение [U]: отображение разницы версий ("Version gap: N release(s) behind")
- Новое: авто-переподпись
mumu-menu.ps1после обновления при наличии сертификата[CRT]— Authenticode-статус больше не падает вNotSignedпосле апдейта (закрыт наход Security-чеклиста П3)
- Фикс [VE]: enable/disable верифицируются свежим
pm list users—am stop-userпри успехе печатает пустоту, текстовый парсинг давал ложный «Failed»
- Новое: меню
[VE]— виртуальное окружение внутри инстанса: вторичный Android-пользователь как изолированное пространство приложений (enable/disable/remove через adb)
- Фикс [RT]: вердикт по свежему перечтению ключа после settle-паузы — работающий плеер может откатить только что записанный
root_permission(гонка flush'а); при откате — честная подсказка
- Новое: меню
[RT]— включение/отключение root для инстанса (root_permissiontoggle, read-back verified)
- Фикс:
.versionбольше не пишется с BOM — оба обновлятора переведены наWriteAllText+UTF8Encoding($false); [UW] больше не будет чинить маркер после каждого обновления
- CDN-фолбэк обновлений (jsDelivr): при отказе
api.github.comскачивание повторяется один раз черезcdn.jsdelivr.net/gh/<repo>@<pinned-commit>/<file>— тот же immutable коммит, без токена, без следования редиректам, каждый байт проходит SHA-256-гейт; тело зеркала сверено с API байт-в-байт. Bootstrap: флаг-NoAuth(анонимный запуск). Выбор зеркала задокументирован в SECURITY.md:raw.githack.comотвергнут (.ps1= 301 → raw-домен)
- SKILL.md: description во фронтматтере закавычен — strict YAML-лоадеры падали на
Features:внутри plain-скаляра («mapping values are not allowed», col 108); текст не изменён, регрессионный тест закрепляет
- Stale-CDN hardening для [U]: тег пинится на commit SHA — и отпечатки SHA-256, и скачивания идут через immutable-коммит; graceful fallback на тег, формулировка [UP]-плана обновлена
- Убран вечный мусор
bootstrap-update.ps1.old: bootstrap удаляет страховочную копию сразу после успешного применения.new, старт-свип меню чистит оба.old-бэкапа, диагностика сообщает о leftover любого из них
- README.md и SKILL.md — UTF-8 без BOM: BOM убран из файлов и из писателя
update-readme.ps1(иначе CI-синк возвращал бы его при каждом прогоне); hygiene-тест закрепляет классы: docs — без BOM,.ps1— с BOM
[UW]опция 5 — «Add missing BOM to .ps1»: ремонт чужих сломанных скриптов — находит.ps1без BOM, но с не-ASCII (ломаются на PS 5.1), показывает список, после подтверждения добавляет байтыEF BB BFбез перекодирования; попутно убран второй экземпляр бага 3-аргументного UTF-8-декодера в опции 4
[UW]: честные вердикты для BOM и безопасность fix-режима: BOM у.ps1— «required for PowerShell 5.1» (не warning),update-journal.logисключён из скана; fix не трогает.ps1, требует подтверждения и корректно декодирует ANSI-файлы в системной кодировке (раньше — потеря не-ASCII при дефолтном UTF-8-чтении)
[UP] Update plan (dry-run)в меню: план того, что сделает [U] — действие, файлы, охват, место на диске, SHA-256-верификация, бэкап, условная запись.version, lock и журнал — без единой мутации. Внутри: параметр-PlanвUpdate-FromGitHub+ чистый рендерерShow-UpdatePlan(4 Pester-теста)
bootstrap-update.ps1 -WhatIf(dry-run): план обновления без скачивания и любых записей — действие (свежая установка / апгрейд / принудительная перекачка с-Force), файлы, источник с пином тега на SHA, статус SHA-256-верификации (и исключение-NoVerify), будущий бэкап, условная запись.version, самоприменение обновлятора; «remote-версия неизвестна» — честный exit 1. T13 в bootstrap-наборе
- Улучшен [DIAG]: info-находки больше не выглядят как проблемы. Живой отчёт: полностью здоровая установка печатала «Problems found: 1 (0 error(s), 0 warning(s), 1 info)» из-за единственной info-заметки «1 of 1 instance(s) running» — теперь вердикт собирает общая функция
Get-DiagSummary: «Status: healthy (1 info note(s) - nothing to fix)» зелёным для чистых/info-only установок; «Problems found: N error(s), M warning(s)» (красный/жёлтый) остался для настоящих проблем, с честными счётчиками по severity. Паритет вbootstrap-update.ps1 -Diagnose - Позитивный статус ADB-моста в [DIAG]: «1 of 1 instance(s) running, ADB bridge ready» (или «NOT ready», предупреждение остаётся отдельной находкой) — раньше экран молчал о мосте, пока тот не падал
- Исправлено: вечный «ADB bridge not ready» на здоровом эмуляторе. Мост MuMu слушает порт, но adb не подключается сам — проба теперь делает явный идемпотентный
adb connectпередdevicesи ищет adb рядом с MuMuManager.exe (nx_main\adb.exe), где он реально лежит. Бонус: все внешние вызовы пробы обёрнуты kill-on-timeout — холодный adb-сервер или зависший MuMu RPC больше не замораживают меню
- Аудит curl-вызовов: строковая сборка через
cmd /cполностью убрана. Все 18 вызовов в меню и 2 в bootstrap переведены на массивы аргументов PowerShell: токен больше не попадает в командную строкуcmd.exe(виден в мониторах процессов), спецсимволы в путях не ломают кавычки, PS 5.1 не склеивает опции (первопричина бага [K] в v1.22.3). Тесты закрепляют: нольcmd /c, каждый curl — через splat@
- Исправлено: [K] показывал «Token invalid!» при валидном токене. Прямые вызовы
curl.exe -s$script:CurlRetryStr ...склеивали-sи retry-опции в ОДИН аргумент (особенность парсинга аргументов PS 5.1) — curl отвечал exit 2 (invalid usage), тело ответа было пустым, и меню объявляло токен недействительным, не сохранив его. Все 5 прямых вызовов (оба пути [K] + выборки releases/tags/compare) переведены на новый хелперInvoke-GitHubApiGet, который строит массив аргументов (склейка аргументов теперь невозможна по построению). Пустой ответ теперь честно сообщает «GitHub did not respond (network problem)» вместо «Token invalid», а реальный отказ различает «Bad credentials» и неожиданный ответ. Проба retry-capability стабилизирована (exit 2 = опция не поддерживается; стабильный URL проверки). Регрессионные тесты: форма массива аргументов, fallback на$script:GitHubToken, классификация exit-кодов пробы, отсутствие склеенного паттерна, проводка [K]
- Честный вердикт при rate-limit (из E2E-дрилла): когда проверка обновлений падает из-за лимита GitHub, оба пути обновления теперь говорят об этом прямо вместо голого «Could not check releases» / «Update check failed».
bootstrap-update.ps1разбирает тело ошибки API и объясняет: без токена лимит — 60 запросов/час на IP (общие сети исчерпывают его быстро), решение — сохранить токен через [K] в меню (DPAPI-шифрование, bootstrap подхватит автоматически) или ждать часового сброса; с токеном — квота исчерпана или токен невалиден, пересохранить через [K].[U]и[V]получили те же token-aware формулировки. T12 в bootstrap-наборе фиксирует проводку вердикта
- Исправлено: ETag-кеш никогда не наполнялся (поймано E2E-дрILLом). GitHub отдаёт заголовок как
ETag:с большой буквы, а парсер ответа ловил только строчный^etag:—$r1.ETagвсегда был пуст, 304-replay #22 не срабатывал, файловый склад #28 оставался пустым. Паттерн теперь регистронезависимый ((?im)^etag:), с регрессионным тестом на оба написания. Симптом до фикса: вечноеETag cache: emptyи перекачка всех тел на каждом deep-чеке
- Персистентный ETag-кеш (issue #28): сессионный ETag-кеш теперь переживает рестарт меню —
.etag-cache.jsonрядом с.versionхранит url → {etag, body, sha256, timestamp}. При загрузке каждое тело валидируется по сохранённому хешу (подделанная/обрезанная запись отбрасывается, а не доверяется); битый/отсутствующий/невалидный по схеме файл деградирует в обычные запросы, никогда не в ошибку. Сохраняются только реальные тела (правило #22 — ошибки API не кешируются), запись best-effort.-Forceотключает кеш-файл — ремонтный запуск всегда качает свежий контент по сети - Сессионный кеш deep-чека в
[ST](issue #28): повторноеdв той же сессии мгновенно воспроизводит закешированный вердикт с пометкой возраста («from session cache, age N min»), сброс при смене маркера версии - Строка состояния кеша в
[ST]:ETag cache: N URL(s), last entry HH:MMпод заголовком экрана — строка из макета #25, теперь настоящая;empty, пока записей нет - 6 новых Pester-тестов (всего 107): round-trip файла, отбрасывание подделанной записи, деградация на битом/отсутствующем/невалидном файле, строка состояния, подавление при
-Force, проводка сессионного кеша
- Авто-диагностика на старте (issue #30): меню один раз за запуск тихо собирает находки
[DIAG]и показывает ОДНУ строку под статус-баром — только если есть ошибки или предупреждения:[auto-diag] Problems found: N error(s), M warning(s) - details: [DIAG]. Info-находки («no .version marker yet», неактивные инстансы) не напоминанают — они остаются в[DIAG]. Здоровая установка не рендерит ничего.MUMU_MENU_NO_AUTODIAG=1отключает проверку; сборщик обёрнут в try/catch — диагностика никогда не блокирует старт, вердикт собирается один раз и кэшируется для всех перерисовок меню. 8 новых Pester-тестов: фильтр severity, подавление info, поведение кэша, проводка на реальном фикстуре, env-отключение
- Устойчивость к нестабильной сети (исправление "Update check failed: Request failed (exit 35)"): встроенный
--retrycurl никогда не повторял сбои TLS-handshake (exit 35) - один сбой сети убивал всю проверку обновлений. Все запросы к GitHub теперь идут с--retry-all-errors(проба один раз за запуск: опция есть только с curl 7.71, старые сборки откатываются на обычный--retry, а не падают на неизвестной опции), ETag-загрузка меню получает PS-уровень ретрая для любой транспортной ошибки,[V]делает 2 попытки, bootstrap печатает код curl при каждом ретрае. Pester-тесты фиксируют классификацию кодов выхода заглушками (35 = поддерживается, 2 = нет, 0 = да, нет curl = деградация) - Устойчивость диагностических проб к
ErrorActionPreference = Stop: запись в stderr от реальногоadb("daemon not running") или curl вызывала терминирующую ошибку внутриInvoke-MumuManagerProbe/_Fetchпод Pester и строгими хостами; теперь перехватывается и трактуется как пустая попытка (поймано живым прогоном тестов)
[RB]Откат из backup (issue #27): список папокbackup\ГГГГММДД_ЧЧММСС(новые сверху, размер + дата + полнота), выбор, подтверждение словомROLLBACK, восстановление 4 файлов. Маркер.versionвыводится из собственного$scriptVerвосстановленного контента — никогда не угадывается (в бэкапах маркера нет; принцип guard v1.20.5). В журнал пишетсяrollback(from = маркер до, to = восстановленный) илиrollback-fail; после предлагается[F]. Чистые хелперы (Get-BackupFolders,Build-RollbackPlan,Invoke-Rollback) покрыты 5 Pester-тестами, включая проверки журналаbootstrap-update.ps1 -Diagnose(issue #29): вход в диагностику без меню — для установок, гдеmumu-menu.ps1не стартует. Печатает отчёт находок в стиле[DIAG](маркер против scriptVer, распарсенного из сырого — возможно битого — текста меню, состояния лока, здоровье журнала, путь MuMu, диск) без сети и без мутаций; exit 0 если чисто, exit 1 при error/warn (скриптабельно для поддержки). T11 в bootstrap-наборе проверяет парсинг из битого файла и проводку- Исправлен ложный позитив проверки готовности ADB-моста (пойман на реальной машине): некоторые сборки MuMu вообще не отдают
adb_versionвinfo -v all, из-за чего v1.21.7 вечно предупреждала «ADB bridge not ready». Проба теперь спрашивает сам ADB —adb devicesпротивadb_portинстанса (только локальный сокет), бинарник ищется вshell\adb.exeMuMu, с ретраем на холодный демон. Регрессионный тест с инъекцией заглушки adb
- Диагностика эмулятора в
[DIAG](issue #32) — один запросMuMuManager info -v allдобавляет к экрану проблем сторону эмулятора: число инстансов, запущены ли, готовность ADB-моста. Нет инстансов / ничего не запущено — info (подсказка создать/запустить), запущенный инстанс без готового ADB-моста — предупреждение (то самое состояние, из-за которого команды внутри эмулятора вродеcurlпадали с «inaccessible or not found»), а MuMuManager, не ответивший чисто, — предупреждение без поломки диагностики. Живой поимок исправлен до релиза: реальный бинарник выдаёт pretty-printed многострочный JSON, который pwsh 7 в пайплайне парсит построчно — проба теперь склеивает строки перед парсингом (регрессионный тест). 9 новых Pester-тестов с честным дочерним процессом (.cmd-заглушка); набор 81 зелёный на PS 5.1 и pwsh 7
- Релиз с фиксом ложного DRIFT глубокой проверки
[ST](07f30fa):Get-IntegrityVerdictчитает вердикт изsummary|-строки отчёта — метаданные больше не маскируются под дрейф. Набор 73 зелёный
- Fix ложного DRIFT в глубокой проверке
[ST](поймано живьём через минуты после релиза): обёртка drift-чека считала информационные строки отчёта (verify-start|,ref-pin|, дажеsummary|ok|) дрейфом, потому что они не начинаются сOK, — полностью здоровая установка сама себе докладывала DRIFT. Теперь выделенныйGet-IntegrityVerdictклассифицирует отчёт по его собственному вердикту (summary|ok|/summary|drift|<файлы>/summary|partial|/error|) — метаданные больше не маскируются под дрейф; проверка, упёршаяся в rate limit, по-прежнему честно деградирует в «unknown». 4 Pester-теста, включая точный регрессионный отчёт из живого поимка; набор 73 зелёный - Статус-экран
[ST](issue #25) — один экран «только чтение»: версия скрипта, локальный маркер, последний релиз, состояние версии, drift-чек, последняя верификация ZIP (из журнала) и сводка журнала. Быстрый путь (Enter) полностью офлайн с честными состояниями «неизвестно/не проверялось»;dв меню добавляет сравнение с релизом и полный drift-чек против тега. Статус собирает тестируемыйGet-InstallStatusс инъекцией сетевых/drift-источников (6 Pester-тестов: быстрый путь, сравнение ok/behind/ahead, drift OK/DRIFT/сбой, отсутствие журнала, FAILED zip-вердикт, проводка меню); набор 69 зелёный. Клавиша[S]осталась за скриншотами — статус это[ST] - README-раздел восстановления (issue #26) — «Восстановление после сбоя обновления»: четыре сценария (HASH MISMATCH, клин маркера, битые файлы/бэкап, отказ блокировки) с таблицей «симптом → причина → действие» по всем вердиктам обновлятора и английской сводкой. Принцип — сначала диагностика (
[ST]/[DIAG]/[F]/[J]), потом действие - Это закрывает milestone v1.21.0 "Drift Hardening & Journal Tooling" (#22 пин/ETag, #23 экспорт журнала, #24 сингл-флайт блокировка, #25 статус-экран, #26 recovery-документация)
- Диагностика проблем
[DIAG]— новый экран «только чтение, только локально»: одним взглядом отвечает, есть ли проблемы с установкой. Проверки: раскладка установки, маркер.versionпротив собственного$scriptVerскрипта (маркер ВПЕРЕДИ контента — ошибка-клин, класс бага лечения v1.20.5, из-за которого обновлятор вечно говорит «Up to date»; контент впереди маркера — предупреждение о прерванном обновлении); ожидающие.new/остатки.old; блокировка обновлений (свежая — предупреждение с PID держателя, stale — info об автоломании, остаток claim — info); здоровье журнала (битые строки, fail-события, счётчикupdate-skipped, размер ротации); окружение MuMu (нетMuMuManager.exe— ошибка, версия ниже минимума — предупреждение) и мало места на диске - Находки собирает чистая функция
Get-ProblemFindingsс путями в параметрах — 9 новых Pester-тестов на фикстурных установках (здоровая/ноль, клин, прерывание, отсутствующие файлы, состояния блокировки, здоровье журнала, MuMu, ожидающие файлы, проводка меню); набор 63 зелёный на PowerShell 5.1 и pwsh 7. Экран ничего не мутирует и не ходит в сеть (онлайн-сравнение остаётся в[F])
- Экспорт журнала
[J](issue #23) — новый пункт[J] -> 5 Exportзаписывает выбранные события в Markdown (таблица для issue, экранирование|), RFC-4180 CSV (заголовок + кавычки для ячеек с запятой/кавычкой/переводом строки) или JSON (объект верхнего уровняgenerator/count/events, поля без изменений). Формат → диапазон (последние 20 / весь / только ошибки, как в просмотре) → путь (Enter =update-journal-YYYYMMDD-HHMMSS.<ext>рядом с журналом). Вывод — UTF-8 с BOM (правило #535), сам журнал не изменяется, повторные экспорты байт-в-байт идентичны - JSON — объект верхнего уровня, а не голый массив: массивы верхнего уровня по-разному парсятся в некоторых потребителях PowerShell 5.1 (проверено живьём — python видел 3 элемента, а pipeline-форма 5.1 оборачивала массив); свойство объекта парсится единообразно в PS 5.1/7, jq и Python. JSON — компактная одна строка; MD/CSV — человеко-форматы
- Тесты: 6 golden-тестов (заголовок/экранирование MD, кавычки CSV, round-trip JSON, BOM + идемпотентность + неприкосновенность журнала, диапазон «только ошибки», ошибка неизвестного формата); набор 54 зелёный на PowerShell 5.1 и pwsh 7
- Сингл-флайт блокировка обновлений (issue #24) —
[U]иbootstrap-update.ps1перед изменением файлов установки захватывают.update-lock(PID + timestamp) атомарнымCreateNew: два параллельных обновлятора (меню в двух окнах, меню + bootstrap) больше не могут повредить.version/скрипты/журнал или применить обновление дважды. Отказ печатает PID держателя и возраст блокировки, пишет в журналupdate-skippedи выходит, ничего не меняя. Блокировка старше 10 минут считается остатком упавшего процесса и безопасно ломается (create-then-break через.update-lock.newзакрывает гонку break/recreate). Снимается вfinally, включая Ctrl+C [J]:update-skippedподсвечивается жёлтым (пропуск — не ошибка), сообщение «ошибок нет» считает пропуски успешными событиями- Тесты: 6 новых Pester-тестов + блок T10 в bootstrap-регрессионном наборе (включая межскриптовые проверки проводки); набор 48 зелёный; проверено живьём (отказ в одном процессе, кросс-процессный отказ через дочерний PowerShell, stale-break, повторный захват после снятия)
- Fix регрессии v1.21.0 в
[F]: пин тега перезаписывал$TagSHA-коммитом — семантическое сравнение.versionотключалось, и здоровый маркер давал ложный DRIFT на каждой проверке (поймано живьём на установке сразу после релиза v1.21.0). Теперь$Tagостаётся читаемым тегом для семантического сравнения, а фетчи контента идут через отдельный закреплённый$FetchRef; добавлен Pester-страж, проверяющий это разделение
[U]/[F]/лечение: закрепление тега за коммитом (issue #22) — все фетчи содержимого?ref=<тег>переписываются на?ref=<sha-коммита>: contents API резолвит ссылку в момент запроса, поэтому CDN-граница может отдать блоб предыдущего коммита минуты после пуша тега (класс багов v1.20.3–v1.20.6); SHA-коммит неизменяем — устаревшее чтение невозможно по построению. Если резолв не удался — проверка идёт по обычному URL тега- ETag-кеш с replay 304 в
Invoke-GitHubGet— повторные фетчи того же URL в одной сессии меню отправляютIf-None-Matchи на304 Not Modifiedвозвращают кешированное тело без передачи; кешируются только реальные тела (не ошибки API) bootstrap-update.ps1: тот же пин тега → SHA — в получении эталонных хешей и в цикле загрузки; резерв — верификация SHA-256 каждого скачанного файла- Исправлено мёртвое лечение
[U]: блок version-fix ссылался на не присвоенные$localText/$remoteText— лечение не могло сработать; теперь локальный текст читается, а фетч закрепляется за коммитом тега - Откат идеи «дешёвых хешей»: media type
application/vnd.github.shaне поддерживается contents API (проверено живьём) — эталонные хеши по-прежнему считаются из тела; повторные фетчи дешевле за счёт ETag-кеша
- Полировка журнала
[J]: пустое полеfromрендерится как(new) -> vX.Y.Z(событие на свежей установке без маркера), а события одного запуска (одинаковые timestamp+actor, напримерupdate-ok+updater-refresh) группируются — продолжение печатается с ASCII-меткой-вместо повторной строки timestamp/actor; глифы боксов не используются (не входят в OEM-кодировки консоли)
- Fix «лечения» маркера
.versionпри запуске: контент, полученный с CDN-границы GitHub, должен сам заявлятьscriptVerтега, иначе лечение отменяется — устаревший блоб предыдущего релиза перестаёт поднимать маркер до тега, чей контент не пришёл (живой случай на v1.20.4: установка «залипла» на «Up to date» с контентом v1.20.3 и маркером v1.20.4; лечение[U]/[F]при расхождении контента остаётся прежним)
[F]: маркер.versionсравнивается семантически — локальный маркер, равный или более новый, чем отстающий маркер тега (бот синхронизации версий приземляется после тега), больше не даёт ложный DRIFT (поймано живьём на v1.20.3)[F]: один повторный запрос перед вердиктом DRIFT — CDN-граница GitHub может отдать устаревший блоб минуты после пуша тега (живой случай:bootstrap-update.ps1был байт-идентичен тегу, а фетч вернул старое содержимое); настоящий дрейф по-прежнему остаётся дрейфом[F]→ проверка ZIP: отсутствующий файл — это не подмена — «No ZIP found … nothing to verify» вместо пугающего «FAILED - do not install»
- Fix пост-проверки хешей bootstrap (v1.20.2): эталонное содержимое тега получалось через
cmd /c-захват вывода curl, который декодирует в консольной OEM-кодировке — кириллица в README/SKILL.md искажалась, и каждый файл давал ложныйHASH MISMATCH(поймано живым прогоном; защита сработала как задумано — обновление было остановлено). Эталоны теперь считаются через байт-точный raw-фетч (curl → temp-файл → UTF-8), как в меню; регресс-тест T9 проверяет не-ASCII тело
Warning
В bootstrap этого релиза есть баг пост-проверки хешей (OEM-кодировка искажает эталонные SHA-256) — каждый файл даёт ложный HASH MISMATCH. Fail-closed, вреда нет; исправлено в v1.20.3. Если вы на v1.20.2: bootstrap-update.ps1 -NoVerify один раз.
- Пост-проверка хешей в
bootstrap-update.ps1(паритет с[U]): после загрузки каждый файл сверяется с ожидаемой SHA-256 из содержимого тега —OK (hash OK)/HASH MISMATCH; расхождение останавливает обновление (.versionне двигается, самоприменение обновлятора отменяется, событиеupdate-failв журнале) - Тот же hashing-контракт, что и в меню (CR/BOM/симметричный TrimEnd) — вынесено в
Get-ContentHash/Get-ExpectedHashes; JSON-ошибки API (rate limit) никогда не принимаются за эталон - Опция
-NoVerifyдля отключения; при недоступности хешей обновление продолжается с пометкойunverifiedв журнале - Регресс-тест T9: векторы SHA-256, симметричный TrimEnd, пропуск rate-limit JSON, wiring
-NoVerify
- Fix post-download hash-проверки
[U](v1.20.0): локальная сторона сверялась без TrimEnd, тогда как ожидаемые хеши считались от TrimEnd-нутого ответа API — любой файл с переводом строки на конце давал ложныйHASH MISMATCHи отменял легитимное обновление. TrimEnd перенесён внутрьGet-ContentHash, все потребители симметричны по построению; регресс-тест в Pester-сьюте
- Прозрачность обновления (issue #17): подтверждение
[U]показывает таблицу ожидаемых SHA-256 всех 5 файлов (из VT-вердиктов релиза), а после загрузки каждый файл сверяется со своей ожидаемой суммой — расхождение останавливает установку до распаковки - Pester-покрытие хелперов (issue #20):
tests/mumu-menu.Tests.ps1— 26+ юнит-тестов чистых функций (Get-ContentHash,Test-InstallationIntegrity,Test-ReleaseZip,ConvertTo-ShellSafe,Compare-ScriptVersion,Format-JournalEvent); отдельный jobpester-unitв CI (tests.yml) - Новый раннер
tests/run-pester.ps1для локальных запусков на PS 5.1 (неинтерактивная установка Pester 5.x)
- Самопроверка релизного ZIP перед установкой (issue #19): переиспользуемая функция
Test-ReleaseZipповторяет на клиенте проверки CI — SHA-256 ZIP против.sha256-сайдкара, точный набор из 5 файлов,$scriptVerиз архива против тега релиза; при любом несоответствии — вердикт «FAILED - do not install» и событиеzip-verify-failв журнале[J] - Три способа проверки:
bootstrap-update.ps1 -VerifyZip <файл.zip>, запрос после[F] Verify installation, либо напрямую в своих скриптах черезTest-ReleaseZip - Регресс-тест T8: 12 ассертов на реальных ZIP-фикстурах — корректный ZIP, подменённый байт, неверный сайдкар, несовпадение версий, неполный набор файлов (с перечислением лишних/недостающих), отсутствие архива
- DNS и HTTP-тесты через busybox-fallback: в образах MuMu 12 нет
nslookup/curl, но есть/system/xbin/busybox— тесты используютbusybox nslookupиbusybox wget(с-q -O /dev/null --timeout, код выхода решает), если нативных инструментов нет - Живая проверка на реальной машине: ping по ICMP фильтруется MuMu NAT (100% loss на все цели при валидном HTTP) — теперь это видно честно: DNS ✓ / HTTP ✓ при FAILED-пингах означает рабочий интернет без ICMP
- Диагностика сети эмулятора честнее: перед тестами определяется наличие инструментов в гостевой ОС (
ping,nslookup/getent,curl) — отсутствие инструмента (замечено вживую: в образе нетcurl) выводится какN/Aс пояснением, а не какFAILEDсети - Парсер ping понимает toybox: вывод Android toybox (
round-trip min/avg/max,2 packets received) распознаётся наравне с busybox/iputils — раньше все цели рисовались FAILED при успешном пинге - Убраны красные блоки ошибок в PowerShell 5.1: stderr гостя (например
curl: inaccessible or not found) больше не оборачивается в NativeCommandError — выводится как обычный текст
- Проверка установки
[F](issue #18): сверка SHA-256 локальных файлов (mumu-menu.ps1,SKILL.md,README.md,bootstrap-update.ps1,.version) с содержимым текущего тега релиза — отчёт OK / DRIFT (с обоими хешами) / MISSING и итог «installation matches vX.Y.Z» или «drift detected (files: ...)» - Устойчивость к API-ошибкам: ответ rate-limit не хешируется как контент (замечено вживую: api.github.com иногда отвечает JSON-ошибкой при curl exit 0) — файл помечается N/A, итог честный partial, а не ложный drift
- Основа в переиспользуемой функции
Test-InstallationIntegrity— покрыта регресс-тестом T7 (14 hermetic-ассертов без сети)
- Самоновляемый обновлятор (issue #21):
bootstrap-update.ps1обновляет сам себя при каждом обновлении —[U]скачивает его в общем списке файлов, bootstrap кладёт новую копию в.newи применяет её в конце успешного прогона - Миграция застрявших инсталляций: установки старше v1.18.10 получают исправленный обновлятор через сам
[U]— закрывает класс «инсталляция застряла на баге обновлятора» (уроки v1.18.8 и v1.19.1) - Журнал: новые события
updater-refresh(применён.newобновлятора) и расширенный startup self-apply в меню (теперь применяется иbootstrap-update.ps1.new, если файл был занят)
- Журнал обновлений [J]: оба обновлятора —
[U]иbootstrap-update.ps1— пишут события в общийupdate-journal.logрядом с установкой: успехи, частичные сбои, автовосстановление.version, самоприменение.new - Просмотр в меню: новый пункт
[J] Update journal— последние 20 событий / весь журнал / только ошибки / открытие в блокноте; экспорт в MD / CSV / JSON ([J] -> 5) - -LogDir: bootstrap-update принимает
-LogDirдля записи журнала в произвольный каталог (если каталог установки только для чтения)
- Milestone «Verification UX» завершён — вся цепочка верификации релиза теперь автоматическая
- VT-скан всех файлов релиза (#14): ZIP +
mumu-menu.ps1+SKILL.mdиз состава ZIP, переиспользование известных объектов по SHA-256 - Вердикты в описании релиза (#15): маркерная секция «VirusTotal verdicts» с таблицей, пермалинками и блоком самопроверки
sha256sum -c, идемпотентно - Автозапуск скана (#16): публикация через
RELEASE_PAT(fallbackGITHUB_TOKEN) — триггерon: release publishedсрабатывает без ручных запусков
- bootstrap-update.ps1 в релизном ZIP: установщик обновлений теперь поставляется в каждом релизе — инсталляция всегда может починить/обновить сам обновлятор (урок v1.18.8: ZIP не содержал фикс обновлятора)
- VT-скан всех файлов релиза (issue #14): CI сканирует не только ZIP, но и
mumu-menu.ps1+SKILL.mdизвлечённые из того же ZIP; повторно известные VT объекты переиспользуются по SHA-256, в step summary — таблица вердиктов с пермалинками
- Sigma #8 (NTFS Alternate Data Stream): MIME-литерал в коде загрузки VT давал подстроку «-stream» в том же скриптблоке, где есть
Set-Content— правило срабатывало ложно; загрузка переведена наcurl.exemultipart, литерал удалён. Скрипт никогда не работал с ADS - Фикс не меняет поведение: те же эндпоинты, тот же DPAPI-ключ, та же логика
Set-Content— только корректный multipart черезcurl.exe
- Fix bootstrap-update: JSON-детектор ложно срабатывал на raw
mumu-menu.ps1(«Received JSON metadata instead of raw file») — raw-скрипт содержит литералы"name":и_linksв собственных API-проверках; теперь JSON-проверки применяются только когда тело ответа начинается с{ - Fix [U] Check for updates: та же защита в обновляторе меню (тот же класс ложного срабатывания)
- Fix .version: bootstrap-update обновляет
.versionтолько при успешной загрузке всех файлов — частичный сбой больше не оставляет.versionвпереди фактической версии скрипта
- Release pipeline: tag-driven Release workflow — ZIP и SHA256 собираются строго из содержимого тега (
git archive), проверка соответствия$scriptVerтегу, идемпотентные перезапуски - VirusTotal в CI: автоматический скан релизного ZIP после публикации (секрет
VT_API_KEY); исправлен невалидный YAML вvirustotal.yml, из-за которого workflow не мог запуститься - CI lint: actionlint + shellcheck по всем workflow (
lint.yml); VT-вердикты v1.18.6 — 0 malicious / 0 suspicious (ZIP,mumu-menu.ps1,SKILL.md); добавленRELEASE-RUNBOOK.md
- Auto-detect MuMuManager.exe path: добавлены generic
shell\пути для автоопределения MuMuManager.exe, registry fallback проверяет иnx_main\, иshell\
- Fix download helpers: убраны stale $LASTEXITCODE проверки, добавлена проверка длины токена
- Fix VT menu: опция [2] Save API key больше не показывает "Invalid selection"
- Fix update download: токен теперь передаётся при скачивании обновлений, добавлено определение rate limit
- SECURITY.md: обновлена политика безопасности — VT API ключ, сетевые эндпоинты, sigma false positive #7, secure installation steps
- [VF] VirusTotal Upload file: загрузка произвольного файла на VirusTotal через API с проверкой существующих результатов, поллингом анализа и отображением вердикта
- Сводная таблица изменений: добавлена для быстрого обзора всех версий
- PSScriptAnalyzer #534: заменён пустой catch block в Upload-VirusTotal на Write-Debug
- SIM check:
[SC]группированная таблица всех SIM-свойств с сводкой состояния - debug.tracing.mcc/mnc: SIM-спуфинг теперь также устанавливает внутренние MCC/MNC эмулятора
- ADB wait loop:
Set-SimOperatorиApply-SavedSimтеперь ждут до 30с пока ADB будет онлайн перед установкой свойств - Shell escaping: символы
&,;,|,$в именах операторов заменяются на_для надёжной работы в shell - PSScriptAnalyzer: подавлены предупреждения
PSUseApprovedVerbsиPSUseDeclaredVarsMoreThanAssignmentsна уровне скрипта - bootstrap-update.ps1: добавлен Bad credentials fallback для API-запросов и скачивания файлов
- VirusTotal интеграция:
[VT]сканирование файлов через VT API,[VK]управление API ключом (DPAPI-шифрование) - Исправлена ошибка DPAPI: добавлен
.Trim()перед расшифровкой токена — исправляет ошибку «incorrect format» с BOM/CRLF - Улучшена загрузка репозитория:
[2]показывает список релизов с датами и описаниями,[3]fallback на скачивание файлов без ZIP - Обновления
[DL] → [4]: сравнение версий, changelog, обновление .version после ZIP - JSON валидация: все пути скачивания проверяют ответ API — предотвращает сохранение JSON-метаданных как файл
- AI-сканер ответ: добавлена таблица-разбор в SECURITY.md для AI/LLM анализаторов
- Удалён Cloudsmith: полностью убрана интеграция с Cloudsmith
- ADB управление:
[AF]передача файлов (push/pull/list),[AS]скриншоты и запись экрана,[AH]интерактивная ADB-сессия - Улучшена загрузка репозитория:
[5]скачивание отдельного файла - Быстрая проверка обновлений: сравнение версий без скачивания скрипта
- Исправлена ошибка скачивания: пустой
Authorizationзаголовок при отсутствии токена - Исправлен пустой catch: PSScriptAnalyzer #518 —
catch {}теперь логирует ошибку
- Исправлен
$scriptVer: переменная версии скрипта определена в глобальной области видимости — меню теперь корректно показывает версию в шапке - Исправлен
$InstalledVersion: переменная версии MuMu теперь инициализируется до проверки —Show-QuickStatusне падает при ошибкеMuMuManager.exe version - Прогресс-бар загрузки
[U]: заменён молчаливыйWebClientнаcurl.exe -#с отображением скорости, размера и прогресса - Защита от краша при запуске: проверка обновлений
Update-FromGitHub -Passiveобёрнута вtry/catch— ошибки сети не убивают скрипт до появления меню
- Consent-гейты для чувствительных операций:
[O] Clear app dataи[9] Uninstall appтеперь требуют явного вводаYESс описанием последствий [A] Run ADB command: session-consent перед первым произвольным ADB-шеллом (команды выполняются только внутри собственной ВМ эмулятора, хост недоступен)- VirusTotal: 0/75 (ps1), 0/75 (zip)
- Безопасность репозитория: добавлена политика безопасности
SECURITY.md(RU/EN) — как приватно сообщить об уязвимости, что не считается уязвимостью, SLA ответа - Code scanning: PSScriptAnalyzer → SARIF → GitHub Code Scanning
.versionсинхронизирован с релизным тегом
Полный журнал изменений: relnotes.md
| Версия | Дата | Изменения |
|---|---|---|
| v1.22.54 | 30.09.2026 | Test-MumuTunnelAB: read-only определение владельца Wintun-туннеля (порты 10808/7890–7893 + цепочка родителей) и предупреждение, если владелец не MuMu; -NoOwnerLookup |
| v1.22.53 | 29.09.2026 | Блок версий EXE в [V]/при старте — только активная установка (Netease1-дубли убраны); синхронизация версий 1.22.53 |
| v1.22.52 | 29.09.2026 | Фикс запуска под Set-StrictMode-хостами; блок версий EXE — только активная установка; CI: guard-аудит сразу после publish |
| v1.22.51 | 29.09.2026 | Автопоиск корней MuMu на любом диске (реестр/ярлыки/процессы/спул); [V] печатает реальные полные пути бинарников |
| v1.22.50 | 29.09.2026 | Автоверсии MuMuPlayer/MuMuNxUpdater EXE при запуске меню (каскад источников, штамп сборки) |
| v1.22.49 | 29.09.2026 | README: раздел про MotW при ручной распаковке ZIP; CI: CodeQL Advanced (язык actions); харденинг Test-ReleaseZip (never-throw) |
| v1.22.48 | 28.09.2026 | Фикс [U]: полный 8-файловый комплект самобновления; [WN] Watch MuMu network + updater (read-only); фикс uint32 и pre-flight в Diag-MumuNx |
| v1.22.47 | 27.09.2026 | Диагностическая троица в ZIP (8 файлов): вотчер MuMu-подключений, A/B-тест туннеля с -Watch, elevated-снимок MuMuNx; контракт файла-сета 5→8 |
| v1.22.46 | 27.09.2026 | Диагностическая троица в ZIP (8 файлов): вотчер MuMu-подключений, A/B-тест туннеля с -Watch, elevated-снимок MuMuNx; контракт файла-сета 5→8 |
| v1.22.45 | 26.09.2026 | CI: deployed-layout Pester-нога (фикстура установленной копии); гейт релиза требует каждую Tests-ногу по имени |
| v1.22.44 | 25.09.2026 | Фикс: отклонённый токен отключается один раз (script-scope) вместо повтора на каждый запрос; guard в Invoke-GitHubApiGet; bootstrap-тень переменной |
| v1.22.43 | 25.09.2026 | CI: самодостаточный release-гейт (диспетчеризация Tests на теге), ZIP-проверка в release-guard, фикс якорного regex'а и дедупликации чек-ранов |
| v1.22.42 | 25.09.2026 | CI: матрица Pester (PS 5.1 + pwsh, пин 5.7.1, канарейка); фикс PublishedAt под PS 5.1 |
| v1.22.41 | 25.09.2026 | Восстановлены сообщения о сбоях получения релиза в [U]/[UP]; удалены мёртвые заголовки Get-ReleaseInfo |
| v1.22.40 | 24.09.2026 | Функция Get-ReleaseInfo + рефакторинг fetch'а релиза в [U]/[UP]; Dependabot-лейблы; upload-sarif v4.38.1 |
| v1.22.39 | 22.09.2026 | [G]: свёртка стек-логгера Lua (ошибка = одна строка); дата v1.22.37 = published_at |
| v1.22.38 | 22.09.2026 | Меню [5]: чистка PSSA — Write-Debug без позиционных параметров |
| v1.22.37 | 22.09.2026 | Меню [5]: панельный редизайн Create (дифф-детекция нового инстанса) |
| v1.22.36 | 21.09.2026 | Меню [G]: поиск по подстроке [6] с подсветкой |
| v1.22.35 | 21.09.2026 | Меню [G]: snapshot-дефолт фильтра errors-only (E) |
| v1.22.34 | 21.09.2026 | Меню [G]: фильтр тишины [5] для logcat |
| v1.22.33 | 21.09.2026 | Меню [3]/[4]: панели с guard'ом и верифицированным итогом shutdown/restart |
| v1.22.32 | 21.09.2026 | Меню [G] View logs: панель, guard logcat, раскраска по уровню |
| v1.22.31 | 21.09.2026 | Меню [2] Launch emulator: панельный редизайн, guard «ALREADY RUNNING», честный итог загрузки |
| v1.22.30 | 21.09.2026 | CI: DevSkim linter (SARIF → Security tab) + SKILL.md refresh |
| v1.22.29 | 21.09.2026 | Фикс [TN]: интерполяция .tag_name внутри $( ) — Partial-вердикт больше не ловит весь объект релиза |
| v1.22.28 | 21.09.2026 | [TN] шаг [5] CDN mirror freshness + CI-воркфлоу cdn-sync (авто-пурж зеркала) |
| v1.22.27 | 21.09.2026 | README: SmartScreen-шаги Chrome/Edge + разблокировка MOTW |
| v1.22.26 | 21.09.2026 | [DIAG]: классификация stale fail-записей журнала — перекрытый успехом fail = historical info |
| v1.22.25 | 21.09.2026 | Фикс [F]: strip signature block перед хешированием — ложный DRIFT на переподписанной установке |
| v1.22.24 | 21.09.2026 | Тегированный снимок [VE]-фиксов, ephemeral token и дедупликации [K] после v1.22.23 |
| v1.22.23 | 20.09.2026 | [FPS] смена FPS + обзор всех инстансов, [RT] redesign UI, [VE] regex fix + UTF-8, [K] ephemeral token, whitespace cleanup |
| v1.22.22 | 20.09.2026 | [TS] сетевой тест скорости, экспоненциальная задержка retry при rate limit, отображение разницы версий |
| v1.22.21 | 18.09.2026 | Авто-переподпись скрипта после обновления при наличии сертификата [CRT] (best-effort) |
| v1.22.20 | 18.09.2026 | Фикс [VE]: вердикт по pm list users, не по тексту am-команды (stop-user печатает пустоту) |
| v1.22.19 | 18.09.2026 | Меню [VE]: виртуальное окружение (вторичный Android-пользователь) — enable/disable/remove |
| v1.22.18 | 18.09.2026 | Фикс [RT]: вердикт по перечтению после settle-паузы (гонка с flush'ем работающего плеера) |
| v1.22.17 | 18.09.2026 | Меню [RT]: enable/disable root для инстанса через root_permission (read-back verified) |
| v1.22.16 | 18.09.2026 | Фикс: .version пишется BOM-less (WriteAllText + UTF8Encoding($false)) обоими обновляторами — [UW] больше не чинит маркер после каждого обновления |
| v1.22.15 | 18.09.2026 | CDN-фолбэк обновлений: jsDelivr-зеркало того же pinned-коммита при отказе api.github.com (без токена, без редиректов, тот же SHA-256-гейт); bootstrap -NoAuth |
| v1.22.14 | 17.09.2026 | SKILL.md: YAML-фронтматтер закавычен (strict-лоадеры падали на Features: в description); регрессионный тест |
| v1.22.13 | 17.09.2026 | [U]: тег пинится на commit SHA (отпечатки + скачивания через immutable-коммит, fallback на тег); [UP]-план честнее |
| v1.22.12 | 17.09.2026 | Убран вечный мусор bootstrap-update.ps1.old: удаление после успешного apply + свип обоих .old на старте меню + DIAG |
| v1.22.11 | 17.09.2026 | README.md/SKILL.md переведены на UTF-8 без BOM; писатель синка не реинтродуцирует BOM; hygiene-тест |
| v1.22.10 | 17.09.2026 | [UW] опция 5: добавление BOM к BOM-less .ps1 с не-ASCII (ремонт для PS 5.1), подтверждение + побайтовая префиксация EF BB BF |
| v1.22.9 | 17.09.2026 | [UW]: BOM у .ps1 честно помечен как обязательный (PS 5.1 ANSI fallback); fix-режим — без .ps1, с подтверждением и ANSI-safe декодированием |
| v1.22.8 | 17.09.2026 | [UP] Update plan (dry-run) в меню: план [U] без мутаций (-Plan в Update-FromGitHub + рендерер Show-UpdatePlan, 4 Pester-теста) |
| v1.22.7 | 17.09.2026 | bootstrap-update.ps1 -WhatIf: dry-run план обновления без скачивания и мутаций; честный случай «remote-версия неизвестна»; T13 в bootstrap-наборе |
| v1.22.6 | 16.09.2026 | Улучшен [DIAG]: info-only установки теперь «Status: healthy», а не ложное «Problems found: 1»; паритет в bootstrap -Diagnose; статус ADB-моста в info-строке эмулятора |
| v1.22.5 | 16.09.2026 | Фикс: вечный «ADB bridge not ready» — явный adb connect + adb рядом с MuMuManager.exe; kill-on-timeout для всех внешних вызовов пробы (холодный adb больше не вешает меню) |
| v1.22.4 | 16.09.2026 | Аудит curl: все вызовы переведены на массивы аргументов (ноль cmd /c), токен убран из командной строки, кавычки/склейки больше не возможны |
| v1.22.3 | 16.09.2026 | Фикс: [K] «Token invalid!» при валидном токене — curl-аргументы больше не склеиваются (Invoke-GitHubApiGet, массив аргументов), честные сообщения о сбое проверки, стабилизирована retry-проба |
| v1.22.2 | 16.09.2026 | Честный вердикт при rate-limit в bootstrap/[U]/[V] — 60 req/hr без токена, [K] как решение, token-aware формулировки |
| v1.22.1 | 16.09.2026 | Фикс: парсер ETag-заголовка стал регистронезависимым (ETag: GitHub) — до этого кеш #22/#28 не наполнялся никогда; поймано E2E-дрILLом |
| v1.22.0 | 16.09.2026 | #28: персистентный ETag-кеш (.etag-cache.json, хеш-валидация, деградация, -Force обходит) + сессионный кеш deep-чека [ST] с пометкой возраста + строка состояния кеша |
| v1.21.10 | 16.09.2026 | #30: авто-диагностика на старте меню — одна строка только при error/warn, MUMU_MENU_NO_AUTODIAG=1 отключает, info остаётся в [DIAG] |
| v1.21.9 | 16.09.2026 | Ретраи curl для нестабильной сети (--retry-all-errors с пробой, exit 35 больше не убивает проверку обновлений); пробы диагностики не падают при ErrorActionPreference = Stop |
| v1.21.8 | 15.09.2026 | #27: [RB] откат из backup с выравниванием маркера по контенту; #29: bootstrap -Diagnose; фикс ложного ADB-предупреждения |
| v1.21.7 | 15.09.2026 | #32: диагностика эмулятора в [DIAG] — инстансы, running, ADB-мост; фикс парсинга многострочного JSON (pwsh 7) |
| v1.21.6 | 15.09.2026 | Fix: [ST] глубокая проверка больше не даёт ложный DRIFT на здоровой установке (вердикт из `summary |
| v1.21.5 | 15.09.2026 | #25: статус-экран [ST] (офлайн-быстрый путь, drift по запросу); #26: README-раздел восстановления; закрыт milestone v1.21.0 |
| v1.21.4 | 15.09.2026 | [DIAG]: диагностика проблем — клин маркера, блокировка, здоровье журнала, MuMu, диск (только чтение, локально) |
| v1.21.3 | 15.09.2026 | issue #23: экспорт журнала [J] (MD / CSV / JSON, UTF-8 BOM, диапазон и путь на выбор, golden-тесты) |
| v1.21.2 | 15.09.2026 | issue #24: сингл-флайт блокировка .update-lock (атомарный create, stale-break 10 мин, finally-снятие, update-skipped в журнал) |
| v1.21.1 | 15.09.2026 | Fix регрессии пина в [F]: $Tag/$FetchRef раздельно — семантический .version снова работает |
| v1.21.0 | 15.09.2026 | issue #22: пин тега → SHA-коммит во всех фетчах, ETag-кеш с 304-replay, fix мёртвого version-fix |
| v1.20.6 | 15.09.2026 | [J]: (new) -> vX.Y.Z для пустого from, группировка событий одного запуска (ASCII-продолжение) |
| v1.20.5 | 15.09.2026 | Fix version-fix: контент должен заявлять scriptVer тега (stale-CDN блоб больше не поднимает маркер) |
| v1.20.4 | 15.09.2026 | [F]: семантический .version, повторный фетч перед DRIFT (stale CDN), честное «nothing to verify» для отсутствующего ZIP |
| v1.20.3 | 15.09.2026 | Fix bootstrap: ложный HASH MISMATCH из-за OEM-кодировки при получении эталонов; байт-точный raw-фетч |
| v1.20.2 | 15.09.2026 | Пост-проверка SHA-256 в bootstrap-update.ps1 (паритет с [U]): hash OK / HASH MISMATCH, -NoVerify, unverified-пометка, тест T9 |
| v1.20.1 | 15.09.2026 | Fix [U]: ложный HASH MISMATCH в пост-проверке (несимметричный TrimEnd), TrimEnd в Get-ContentHash |
| v1.20.0 | 15.09.2026 | Milestone Update Trust: SHA-256 таблица в подтверждении [U] + сверка после загрузки (#17), Pester-покрытие хелперов + CI job (#20) |
| v1.19.6 | 15.09.2026 | Самопроверка релизного ZIP (#19): Test-ReleaseZip (sha256-сайдкар, набор файлов, scriptVer), -VerifyZip в bootstrap, запрос в [F], тест T8 |
| v1.19.5 | 15.09.2026 | Диагностика сети: busybox-fallback для DNS/HTTP (busybox nslookup, busybox wget), честный отчёт при ICMP-фильтрации |
| v1.19.4 | 15.09.2026 | Диагностика сети: N/A вместо FAILED при отсутствии инструментов в гостевой ОС, парсер toybox-ping, без красных блоков ошибок в PS 5.1 |
| v1.19.3 | 14.09.2026 | Проверка установки [F] (#18): сверка файлов с тегом релиза, отчёт OK/DRIFT/MISSING, защита от API-ошибок |
| v1.19.2 | 14.09.2026 | Самоновляемый обновлятор (#21): [U] и bootstrap обновляют bootstrap-update.ps1, .new-самоприменение, события updater-refresh |
| v1.19.1 | 14.09.2026 | Журнал обновлений: общий update-journal.log для [U] и bootstrap, просмотр в меню [J], санитизация и ротация лога |
| v1.19.0 | 14.09.2026 | Milestone Verification UX: автоскан всех файлов, вердикты в описании релиза, автозапуск скана (#14 #15 #16) |
| v1.18.10 | 14.09.2026 | bootstrap-update.ps1 в релизном ZIP; VT-скан ZIP + ps1 + SKILL.md в CI (issue #14) |
| v1.18.9 | 14.09.2026 | Sigma #8 (NTFS ADS): убран MIME-литерал «-stream», VT-загрузка через curl.exe multipart |
| v1.18.8 | 14.09.2026 | Fix bootstrap-update/[U]: JSON-детектор самоматчился на raw ps1; .version только при полном успехе |
| v1.18.7 | 14.09.2026 | Release pipeline: tag-driven CI, VT-скан релиза в CI, actionlint/shellcheck, RELEASE-RUNBOOK |
| v1.18.6 | 04.09.2026 | Auto-detect MuMuManager.exe: generic shell\ paths + registry shell fallback |
| v1.18.5 | 04.09.2026 | Fix download helpers: stale $LASTEXITCODE, token length check |
| v1.18.4 | 04.09.2026 | Fix VT меню: [2] Save API key «Invalid selection» fix |
| v1.18.3 | 04.09.2026 | Fix update download: token в загрузках, rate limit detection |
| v1.18.2 | 04.09.2026 | SECURITY.md: VT API, сетевые эндпоинты, sigma #7, secure installation |
| v1.18.1 | 04.09.2026 | [VF] загрузка файлов на VirusTotal, сводная таблица, PSScriptAnalyzer #534 fix |
| v1.18.0 | 04.09.2026 | [SC] проверка SIM, debug.tracing.mcc/mnc, ADB wait loop, shell escaping, PSScriptAnalyzer suppress, bootstrap Bad credentials fallback |
| v1.13.29 | 31.08.2026 | [VT] VirusTotal scan, [VK] API ключ, DPAPI fix, JSON валидация, AI-сканер ответ, удалён Cloudsmith |
| v1.13.28 | 30.08.2026 | [AF] ADB файлы, [AS] скриншоты, [AH] ADB shell, быстрая проверка обновлений, прогресс-бар загрузки |
| v1.13.27 | 29.08.2026 | Исправлены $scriptVer и $InstalledVersion, прогресс-бар [U], защита от краша при запуске |
| v1.13.26 | 26.08.2026 | Consent-гейты для [O] и [9], session-consent для [A] ADB shell |
| v1.13.25 | 26.08.2026 | SECURITY.md (RU/EN), PSScriptAnalyzer → SARIF → GitHub Code Scanning |
- VirusTotal (v1.22.47, 28.09.2026): 0 malicious / 0 suspicious — Status: CLEAN — релизный ZIP,
mumu-menu.ps1и SKILL.md из его состава просканированы CI автоматически после публикации; отчёты — в таблице ниже и в описании релиза - Скан запускается автоматически после публикации релиза: Release workflow публикует релиз с
RELEASE_PAT(секрет), чтобы сработал триггерon: release published— GitHub подавляет триггеры для релизов, созданныхGITHUB_TOKEN - CI автоматически сканирует релизный ZIP, а также
mumu-menu.ps1иSKILL.mdиз его состава (virustotal.yml, секретVT_API_KEY); известные VT объекты переиспользуются по SHA-256; вердикты и пермалинки автоматически публикуются в описании релиза (маркерная секция «VirusTotal verdicts», идемпотентно) - Встроенное сканирование:
[VT] VirusTotal scan— проверяет файлы через VT API - Автоматизированный контроль (полный список — в SECURITY.md): еженедельный PSScriptAnalyzer с SARIF в Security-таб (пн 06:00 UTC), CI VirusTotal-скан каждого релиза, еженедельный Release guard (комплектность релизов + побайтовая сверка ZIP последнего релиза с тегом), групповые Dependabot-обновления экшенов, actionlint + shellcheck на все workflows
| Файл | SHA-256 | Malicious | Suspicious | Отчёт |
|---|---|---|---|---|
релизный MuMuManager-CLI-Menu-v1.22.47.zip |
ce1dae8aaca8…2baa |
0 | 0 | отчёт |
mumu-menu.ps1 (v1.22.47) |
9ebaaf8acda0…a47c |
0 | 0 | отчёт |
SKILL.md (v1.22.47) |
b3e23bb1aa0c…bac9 |
0 | 0 | отчёт |
Актуальные вердикты каждого релиза — в секции «VirusTotal verdicts» на странице релиза; ссылка на свежий релиз: Releases/latest.
| Файл | SHA-256 | Движков | Отчёт |
|---|---|---|---|
релизный MuMuManager-CLI-Menu-v1.19.0.zip |
cef030100b0c…cd28 |
65 | отчёт |
mumu-menu.ps1 (v1.19.0) |
9ec8749a1037…3770 |
61 | отчёт |
релизный MuMuManager-CLI-Menu-v1.18.10.zip |
a1e667c56c4a…f11c |
66 | отчёт |
mumu-menu.ps1 (v1.18.10) |
ad98ccb10814…a46 |
62 | отчёт |
релизный MuMuManager-CLI-Menu-v1.18.9.zip |
a4e6312fdc31…6922 |
65 | отчёт |
mumu-menu.ps1 (v1.18.9) |
9188407bd1d1…f181 |
62 | отчёт |
релизный MuMuManager-CLI-Menu-v1.18.8.zip |
93e6cc95eb4a…8f21 |
65 | отчёт |
mumu-menu.ps1 (v1.18.8) |
f1eb73e49f70…ea70 |
61 | отчёт |
релизный MuMuManager-CLI-Menu-v1.18.7.zip |
63b1dce6583b…7596 |
66 | отчёт |
mumu-menu.ps1 (v1.18.7) |
0c8427f956c8…45b2 |
62 | отчёт |
релизный MuMuManager-CLI-Menu-v1.18.6.zip |
42a5bb22d3a1…50cc |
66 | отчёт |
mumu-menu.ps1 (v1.18.6) |
cff9e179648c…6664 |
60 | отчёт |
SKILL.md (v1.18.6) |
ce1f9c9ae730…7382 |
61 | отчёт |
mumu-menu.ps1 (v1.13.29) |
874542b1ae26…d251 |
62 | отчёт |
bootstrap-update.ps1 |
2d4430c15c7b…be30 |
60 | отчёт |
mumu-menu.ps1 (v1.13.26) |
318132d22881…f8c |
75 | отчёт |
| Файл | SHA-256 | Движков | Отчёт |
|---|---|---|---|
mumu-menu.ps1 (v1.13.26) |
318132d22881…f8c |
75 | отчёт |
релизный MuMuManager-CLI-Menu-v1.13.26.zip |
c10e5da08f30…ec5 |
75 | отчёт |
mumu-menu.ps1 (v1.13.25) |
825982aa50e3…652 |
75 | отчёт |
релизный MuMuManager-CLI-Menu-v1.13.25.zip |
08be745ca928…4d3 |
75 | отчёт |
mumu-menu.ps1 (v1.13.14) |
97cfac7eb2ce…912 |
75 | отчёт |
релизный MuMuManager-CLI-Menu-v1.13.14.zip |
0da34de075d4…bde |
74 | отчёт |
mumu-menu.ps1 (v1.13.7) |
4cfb3fd0679d…1f0c |
60 | отчёт |
релизный MuMuManager-CLI-Menu-v1.13.7.zip |
5d7ae270346a…5a9e |
64 | отчёт |
mumu-menu.ps1 (v1.13.6) |
f3e00f73e2fc…f6fab4 |
60 | отчёт |
mumu-menu.ps1 (v1.13.4) |
201de575dcd3…c3081 |
60 | отчёт |
mumu-menu.ps1 (v1.13.3) |
35fd20035859…4ec1e |
44+ | отчёт |
update-readme.ps1 |
618c48dc0809…e6854 |
60 | отчёт |
README.md |
868a1a7db4cf…03ddf |
60 | отчёт |
SKILL.md |
1e60372d8fbe…8f2e7b |
60 | отчёт |
релизный MuMuManager-CLI-Menu-v1.13.5.zip |
940264ef8e12…02cc |
64 | отчёт |
| URL | Вердикт | Комментарий владельца | Отчёт |
|---|---|---|---|
cdn.jsdelivr.net/…@v1.22.15/mumu-menu.ps1 (официальное зеркало, тег) |
0 malicious / 0 suspicious (61 harmless) | ✅ + harmless-голос (2026-09-18) | отчёт |
cdn.jsdelivr.net/…@4dbe83cb…/mumu-menu.ps1 (официальное зеркало, commit SHA) |
0 malicious / 0 suspicious (61 harmless) | ✅ + harmless-голос (2026-09-18) | отчёт |
raw.githubusercontent.com/…/main/mumu-menu.ps1 (историческая ссылка) |
2 flag'а по шаблону адреса, файл чист | ✅ FALSE POSITIVE (v1.13.x) | отчёт |
github.com/…/releases/download/v1.22.15/…zip (релизный ассет) |
0 malicious / 0 suspicious (59 harmless) | ✅ + harmless-голос (2026-09-18) | отчёт |
github.com/…/releases/download/v1.22.15/…zip.sha256 (сайдкар) |
0 malicious / 0 suspicious (59 harmless) | ✅ + harmless-голос (2026-09-18) | отчёт |
URL-сканеры (SafeToOpen, Chong Lua Dao) помечают ссылки вида raw.githubusercontent.com/.../*.ps1 как «malicious» по шаблону адреса, не анализируя содержимое — файл по ссылке чист (0/61). Браузеры (Chrome/Edge Safe Browsing) показывают «mumu-menu.ps1 может навредить вашему устройству» по той же причине — тип файла (.ps1 = исполняемый скрипт), не вердикт по содержимому. В ответ:
- оставлен комментарий владельца к URL-объектам на VirusTotal: raw-ссылке (v1.13.x) и обеим jsDelivr-ссылкам v1.22.15 (тег + commit SHA; обе просканированы: 0 malicious / 0 suspicious, 61 harmless, категория «computers & software»);
- начиная с v1.13.3 самообновление скачивает файлы только через официальный
api.github.comи больше не обращается кraw.githubusercontent.com; - с v1.22.15 при отказе API скачивание уходит на зеркало
cdn.jsdelivr.netтого же pinned-коммита (без токена, без редиректов, тот же SHA-256-гейт) — см. «Безопасность обновлений» в SECURITY.md; - кандидат
raw.githack.comпроверен и отвергнут:.ps1отдаётся только 301-редиректом наraw.githubusercontent.com, т.е. фактический источник — тот самый raw-домен; - для ручного скачивания добавлен способ №4 (jsDelivr CDN) и примечание о типовой природе браузерного предупреждения — см. раздел «Установка» выше.
- Самообновление скачивает только текстовые файлы (.ps1/.md), никаких исполняемых файлов
- GitHub-токен хранится только в шифрованном виде (Windows DPAPI, CurrentUser); плейнтекст не записывается на диск
- Нет обфускации, автозагрузки, задач планировщика и модификаций сертификатов
- Подмена модели и генерация идентификаторов предназначены для приватности и тестирования приложений на собственных инстансах пользователя
Каждый файл релиза проверен VirusTotal. Нажмите на ссылку, чтобы увидеть актуальный вердикт:
| Файл | SHA-256 | VirusTotal |
|---|---|---|
MuMuManager-CLI-Menu-v1.22.21.zip |
5831eb75...deadb8e |
|
mumu-menu.ps1 |
87dae0af...aa3530 |
|
bootstrap-update.ps1 |
d34185cb...c844e |
VT-сканирование запускается автоматически для каждого релиза (GitHub Actions). Вердикты также публикуются в описании релиза на странице Releases.
Статические LLM-обзорщики могут помечать утилиту как «suspicious» из-за назначения функций (спуфинг идентификаторов, менеджер токена, самообновление), а не из-за поведения кода. Вот разбор каждого担忧:
| Тревога AI-сканера | Реальность |
|---|---|
| «Spoofing device identifiers» | Функция приватности для СОБСТВЕННЫХ экземпляров эмулятора. Требует подтверждения «OK». Не влияет на реальные устройства. |
| «Handling sensitive information» | Токен GitHub зашифрован через Windows DPAPI (CurrentUser scope). Расшифровывается только тем же пользователем Windows. Плейнтекст не хранится. |
| «Extensive access to emulator internals» | Все операции используют официальный CLI Netease (MuMuManager.exe) и стандартный adb.exe. Нет reverse engineering. |
| «Risk of misuse» | Каждая чувствительная операция требует ввода «OK». Скрипт документирует намерения в комментариях и политике безопасности. |
| «Self-update mechanism» | Обновления ТОЛЬКО из tagged GitHub Releases с пином на commit SHA и проверкой SHA-256 каждого файла; фолбэк-транспорт — то же зеркало того же коммита без токена. Нет выполнения кода из недоверенных источников. |
| «Certificate management» | Self-signed CodeSigning сертификат только для подписи скрипта. Явное действие через меню [CRT]. |
При скачивании .ps1-файлов через браузер Windows SmartScreen показывает предупреждение «mumu-menu.ps1 может нанести вред вашему устройству». Это ложное срабатывание — SmartScreen блокирует по репутации URL/расширения, а не по анализу содержимого.
Как обойти — шаги по браузерам:
- Chrome: в карточке предупреждения нажмите «Подробнее» → «Сохранить в любом случае». Если файл уже в списке загрузок —
⋯справа от него → «Сохранить» → «Всё равно сохранить» - Edge: нажмите «Сохранить», затем в тосте «Показать ещё» → «Все равно сохранить». Если файл уже в списке загрузок —
⋯→ «Сохранить» → «Все равно сохранить» - Общее: если показана только кнопка «Удалить», раскройте «Сведения»/«Подробнее» — рядом появится кнопка сохранения
Разблокировка MOTW (Mark-of-the-Web):
Скачанный из интернета файл получает метку MOTW, и Windows может заблокировать его запуск (ExecutionPolicy RemoteSigned не выполняет файлы с меткой из интернета). Снимите метку одним из способов:
- Проводник: правой кнопкой по файлу → Свойства → внизу отметьте «Разблокировать» → OK
- PowerShell:
Unblock-File .\mumu-menu.ps1(или разом для всех скриптов:Get-ChildItem *.ps1 | Unblock-File) - Проверить наличие метки:
Get-Item .\mumu-menu.ps1 -Stream Zone.Identifier -ErrorAction SilentlyContinue— вывод означает, что метка ещё стоит
Альтернативы без SmartScreen:
- Скачайте ZIP-архив с страницы релиза — ZIP SmartScreen обычно не блокирует
- Используйте
git clone https://github.com/genrihx2/MuMuManager-CLI-Menu.git - Используйте bootstrap-update.ps1 для автоматической установки
Ключевые факты:
- Сетевые операции — по минимально необходимому списку эндпоинтов (полная таблица с механизмами — в SECURITY.md):
api.github.com(проверка версий, загрузка обновлений, токен),cdn.jsdelivr.net(только транспортный фолбэк того же pinned-коммита — без токена и без редиректов),www.virustotal.com(VT-интеграция),github.com(clone/ссылки), timestamp-сервер при подписании и [TN]-пробы по явному действию; стартовая проверка — read-only, загрузка только по явному выбору[U]с подтверждением - Токен хранится исключительно DPAPI-шифрованным; плейнтекст не пишется и при обнаружении мигрируется/удаляется
- Нет инъекций, доступа к критическим системным процессам, дампов памяти, обфускации, encoded-команд, persistence
- Эмулятор управляется официальным CLI Netease (
MuMuManager.exe); ADB-команды выполняются только по явному запросу пользователя внутри виртуальных машин - Мультидвижковый вердикт VirusTotal: 0 malicious / 0 suspicious (актуальные счётчики — в таблице выше)
- Microsoft Defender: false positive appeal подтверждён (Submission ID:
e7863737-b31e-4a0b-a4ae-6b8316ea00c8). Microsoft: «Our scanners show no positive detection — submission closed with no further action pending». Definitions v1.459.282.0: файл чистый - Подробнее: SECURITY.md
| Файл | Описание |
|---|---|
mumu-menu.ps1 |
Основной скрипт с интерактивным меню |
update-readme.ps1 |
Синхронизация README с меню/версией скрипта |
.github/workflows/sync-readme.yml |
Автообновление README при пуше (GitHub Actions) |
.github/workflows/release.yml |
Автоматические релизы при смене версии |
.github/workflows/virustotal.yml |
VT-скан всех файлов релиза + вердикты в описании релиза |
.github/workflows/security-scan.yml |
PSScriptAnalyzer → SARIF → Code Scanning |
.github/workflows/lint.yml |
actionlint + shellcheck по всем workflow |
.github/workflows/tests.yml |
Регресс-тесты обновлятора (windows-latest) |
.github/workflows/changelog-check.yml |
Проверка консистентности changelog: строкам таблицы соответствуют секции «Что нового» |
tests/test-bootstrap-update.ps1 |
Регресс-тест JSON-детектора обновлятора |
RELEASE-RUNBOOK.md |
Runbook релизного конвейера (RU/EN) |
SECURITY.md |
Политика безопасности (RU/EN) |
relnotes.md |
Журнал изменений |
.gitattributes |
Нормализация окончаний строк (LF) |
backup/, backups/ |
Локальные копии (не коммитятся) |
SKILL.md |
Документация навыка для AI-агентов |
bootstrap-update.ps1 |
аварийное обновление (восстановление при поломке [U]) |
.github-token.dpapi |
Токен GitHub DPAPI-шифрованный (не коммитится) |
.vt-apikey.dpapi |
API ключ VirusTotal DPAPI-шифрованный (не коммитится) |
Блок меню и версия в README генерируются автоматически из
mumu-menu.ps1(update-readme.ps1, запускается локально и в GitHub Actions).
MIT License
MuMu Manager CLI Menu is an interactive PowerShell menu for managing Netease MuMu Emulator 6.x through the official MuMuManager.exe CLI on Windows 10/11 (PowerShell 5.1+).
Features: emulator start/stop/restart, instance cloning/renaming/deletion, APK install/uninstall (including batch to all instances), ADB commands with file transfer, screenshots and screen recording, interactive ADB shell, data export and backup with ZIP compression, device-model spoofing, SIM operator/country presets (38 + custom), random IMEI/Android ID/MAC generation, window management, log viewing (files + live logcat), a DPAPI-encrypted GitHub token manager, Authenticode self-signing ([CRT]), and a VirusTotal integration ([VT] scan / [VF] upload).
Installation: run the one-liner below, or grab a release ZIP — every release is CI-built strictly from its tag (git archive) and contains exactly eight files: mumu-menu.ps1, bootstrap-update.ps1, README.md, SKILL.md, .version, Watch-MumuConnections.ps1, Test-MumuTunnelAB.ps1, Diag-MumuNx.ps1.
irm https://raw.githubusercontent.com/genrihx2/MuMuManager-CLI-Menu/main/mumu-menu.ps1 -OutFile $env:TEMP\mumu-menu.ps1; & $env:TEMP\mumu-menu.ps1SmartScreen warning: When downloading .ps1 files, Windows SmartScreen may show "mumu-menu.ps1 can harm your device". This is a false positive — SmartScreen blocks by URL reputation and file extension, not by content analysis. Chrome: in the warning card expand "Details" → "Save anyway" (or download tray ⋯ → "Keep" → "Keep anyway"). Edge: "Save" → "Show more" → "Keep anyway". The saved file carries Mark-of-the-Web; unblock it via file Properties → Unblock or Unblock-File .\mumu-menu.ps1 before running. Alternatively grab the ZIP from the latest release — ZIP downloads are not SmartScreen-blocked.
Security: updates come only from tagged GitHub Releases, pinned to their commit SHA, with SHA-256 verification of every downloaded byte; when the API is unreachable, one transport retry goes through the cdn.jsdelivr.net mirror of the same pinned commit (no token, no redirect-following). Browser warnings on .ps1 downloads are file-type triggers, not content verdicts — every release carries CI VirusTotal verdicts in its body (v1.22.47: 0 malicious / 0 suspicious, Status: CLEAN, CI scan 2026-09-28). Microsoft Defender false positive appeal confirmed (Submission ID: e7863737-b31e-4a0b-a4ae-6b8316ea00c8): Microsoft stated «Our scanners show no positive detection — submission closed with no further action pending». Definitions v1.459.282.0: file is clean. Continuous automated controls: weekly PSScriptAnalyzer (SARIF → Security tab), CI VirusTotal scan per release, weekly Release guard (release completeness + byte-for-byte ZIP-vs-tag audit), grouped Dependabot action updates, actionlint + shellcheck on all workflows. The full policy («Reporting a Vulnerability», SLA, safe harbor), endpoint table, threat model and Sigma false-positive analysis are in SECURITY.md; the release pipeline runbook in RELEASE-RUNBOOK.md.
Updater: [U] Check for updates compares the local .version against GitHub release tags and downloads only from tagged releases after explicit confirmation, with backups of the previous files in backup\<timestamp>\. bootstrap-update.ps1 ships inside every release ZIP as a recovery path if the in-menu updater ever breaks. Docs are maintained in Russian with English summaries; the menu itself is in English.