W-Fix.App— WPF-интерфейс, выбор цели и сценария, отображение прогресса.W-Fix.Core.Models— данные принтеров, журнал и типизированные результаты операций.W-Fix.Core.Services— обнаружение принтеров, Active Directory и выполнение PowerShell.W-Fix.Core.Fixers— прикладные сценарии диагностики и исправления.W-Fix.Core.Abstractions— стабильные контракты транспорта, инвентаризации, диагностики, ремонта и отчётов.W-Fix.Core.Remote— WinRM/WSMan-сессии, capability preflight и снимок печатной подсистемы.W-Fix.Core.Diagnostics— правила, формирующие находки только из наблюдаемых фактов.W-Fix.Core.Repair— планирование, адаптер двенадцати v2-фиксеров и ограниченное пакетное выполнение.W-Fix.Core.Catalog— встроенный и подписанный онлайн-каталог известных проблем Windows.W-Fix.Core.Pairing— TLS-транспорт, подписанный offline-обмен, парная диагностика и двухузловая saga.
UI не должен самостоятельно определять успешность системной команды. Источником истины является
PowerShellExecutionResult, а итог многошагового фиксера вычисляется из результатов всех выполненных шагов.
PowerShellEngine поддерживает два режима:
- Встроенный runspace PowerShell SDK — в том числе для
Invoke-Commandна удалённой машине. - Внешний Windows PowerShell 5.1 — для Windows-модулей, несовместимых со встроенным Core-runspace.
Оба режима имеют общий десятиминутный таймаут по умолчанию. Пользовательская отмена пробрасывается как
OperationCanceledException; таймаут возвращается как неуспешный PowerShellExecutionResult с
TimedOut = true. Внешний процесс при этом завершается вместе с дочерними процессами.
Скрипты используют префиксы [OK], [INFO], [WARN] и [ERROR]. Даже если PowerShell-скрипт перехватил
исключение, строка [ERROR] делает результат неуспешным. Служебный progress-CLIXML Windows PowerShell 5.1
в stderr не считается ошибкой.
- Не сообщать
Success, если обязательный шаг завершился неуспешно. - Не скрывать ошибку обязательного шага за успешным перезапуском Spooler.
- Ограничивать удаление файлов только ресурсами подсистемы печати.
- Каждый фиксер, изменяющий реестр, реализует
ISystemStateChangingFixerи точно объявляет затрагиваемые значения, разделы и ACL. Новое изменение реестра без дополнения плана снимка считается дефектом. - Любой новый сценарий должен иметь тестируемую логику определения результата.
Перед запуском изменяющего реестр фиксера SystemStateBackupService сохраняет только затрагиваемое состояние,
а не экспортирует реестр целиком. Снимок содержит state.clixml, manifest.json, при необходимости .reg-файлы
и автономный restore.ps1. Каталог создаётся на целевой машине в
%ProgramData%\W-Fix\Backups\<время>_<фиксер>_<id>.
Ошибка снимка выводится как заметное предупреждение, но не превращает W-Fix в режим «только диагностики»: пользовательский ремонт продолжается. После успешного снимка команда «Откат» восстанавливает значения, удаляет значения, которых до исправления не существовало, возвращает ACL и импортирует сохранённые разделы. После восстановления перезапускается Print Spooler.
UI сохраняет выбранные фиксер, принтер и компьютер в начале операции. Поэтому смена выбора во время исполнения не может направить часть одного сценария на другую цель. Повторные загрузки принтеров, очередей и компьютеров отменяют устаревшие запросы, чтобы поздний ответ не перезаписывал более актуальное состояние.
PowerShell Remoting выполняет команды в сервисном контексте учётной записи администратора. Поэтому обычный
HKCU: и вызовы WScript.Network из WinRM не относятся к рабочему столу пользователя, вошедшего на целевой ПК.
Фиксеры принтера по умолчанию используют отдельный InteractiveUserPowerShellService:
- Через WinRM определяется интерактивный пользователь и его SID.
- Администратор сохраняет HKCU этого пользователя через
Registry::HKEY_USERS\<SID>; restore-скрипт хранит уже разрешённый путь, поэтому откат возвращается в тот же профиль. - На целевом ПК создаётся временная задача
W-Fix-Interactive-<id>с типом входаInteractiveи уровнемLimited. Пароль пользователя не запрашивается и не сохраняется; используется существующий токен сеанса. - Пользовательская часть выполняет
WScript.Network/PrintUI, пишет UTF-8 журнал и подтверждает фактически назначенный принтер. Код задачи и маркеры[ERROR]проверяются независимо. - Административные действия — исправление ACL и перезапуск Spooler — остаются в WinRM-контексте.
- Временная задача и файлы удаляются в
finally; при отмене выполняется дополнительная best-effort очистка.ExecutionTimeLimitограничивает процесс даже при обрыве управляющего соединения.
Удалённый пользовательский фикс требует включённых WinRM и Task Scheduler, административного доступа и уже вошедшего пользователя. Если интерактивного сеанса нет, операция завершается явной ошибкой — W-Fix не сообщает ложный успех для HKCU администратора.
App.xaml.cs является composition root. ViewModel больше не создают системные сервисы самостоятельно.
Пользовательский поток имеет фиксированные границы:
TargetDescriptorсоздаётся из ручного списка либо объекта Active Directory.IRemotePreflightServiceпроверяет DNS, WinRM, административный токен, CIM, Spooler, Task Scheduler, интерактивного пользователя, pending reboot и место на системном диске. Ping остаётся справочным сигналом.IPrinterInventoryServiceсобирает ОС/build/UBR, KB, очереди, задания, порты, драйверы, политики, Protected Print Mode и свежие ошибки PrintService.IDiagnosticRuleсоздаётDiagnosticFindingс доказательствами, уверенностью и локальными action ID.IRepairPlannerисключает действия, для которых цель не имеет требуемых capabilities.IRepairExecutorограничивает параллелизм, создаёт снимок до мутации, выполняет шаг, повторно диагностирует цель и при неуспехе откатывает её независимо от остальных машин.IRunReportServiceсохраняет JSON/HTML в%ProgramData%\W-Fix\Runs\<RunId>.
Каталог известных проблем декларативен и не содержит скриптов. Даже корректно подписанная запись может выбрать только действие, уже скомпилированное и зарегистрированное в W-Fix.
IPairSessionTransport создаёт одноразовую TLS-сессию с временным ECDSA P-256 сертификатом. Клиент проверяет
pin публичного ключа из .wfixpair, оба окна показывают вычисленный шестизначный код, а прикладные сообщения
разрешаются только после двух подтверждений. Протокол принимает только версионированные DTO и встроенные
идентификаторы pair.*; строки PowerShell и пароли через него не передаются.
IPairInventoryService проверяет только явно названного соседа. IPairRepairExecutor выполняет общий план как
двухузловую saga: remote host-side шаги проходят через PairAgentCommandLoop, local client-side шаги выполняются
локальным dispatcher. До каждого изменения создаётся checkpoint. Ошибка, отмена, timeout или потеря соединения
вызывают обратный rollback и явный abort; commit отправляется только после повторной проверки всех шагов.
На хосте действует временное Firewall-правило для текущего EXE, точного порта, LocalSubnet и Private/Domain.
В offline-режиме ECDSA-подписанный снимок защищён от изменения, но обе стороны ремонтируются раздельно, поэтому
общий автоматический rollback недоступен. Пароль HOST\\User сохраняется напрямую в Windows Credential Manager.
Reversible— обычное подтверждение плана и обязательный снимок.Disruptive— заметная маркировка (например, временная остановка Spooler).Irreversible— дополнительный диалог; сюда относятся удаление заданий или пакетов драйверов.- Protected Print Mode не переключается автоматически: режим может удалить несовместимые очереди и драйверы.
- Удаление Windows Update не является обычным действием; допускается только отдельным экспертным сценарием.