Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ jobs:
runs-on: windows-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- name: Setup .NET 8
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v6
with:
dotnet-version: 8.0.x

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@
| 12 | **Принтер по умолчанию** | Default printer | Сброс реестра + `SetDefaultPrinter` |

### Плюс:
- 🌐 **Удалённые машины** — применяй фиксеры через WinRM/PowerShell Remoting
- 🌐 **Удалённые машины** — системные шаги через WinRM, а пользовательские настройки принтера — в реальном интерактивном сеансе
- 🔍 **Обнаружение принтеров** — CIM / WMI / Get-Printer (тройной fallback)
- 📋 **Полный лог** — каждый шаг фиксера отображается в реальном времени
- ↩️ **Точечный откат** — снимок изменяемых ключей реестра и кнопка восстановления после фикса
- 🗂 **Active Directory** — обзор принтеров в домене

---
Expand Down Expand Up @@ -99,6 +100,8 @@ W-Fix/
│ │ ├── Services/
│ │ │ ├── WmiService.cs # Обнаружение принтеров (CIM/WMI/PS)
│ │ │ ├── PowerShellEngine.cs # Встроенный PS SDK + внешний fallback
│ │ │ ├── InteractiveUserPowerShellService.cs # Remote-команды в сеансе пользователя
│ │ │ ├── SystemStateBackupService.cs # Снимок реестра + restore.ps1
│ │ │ └── FixerRegistry.cs # Регистрация и поиск фиксеров
│ │ └── Models/ # PrinterInfo, FixResult, LogEntry ...
│ └── W-Fix.App/ # WPF UI (MVVM + CommunityToolkit)
Expand Down
42 changes: 40 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,49 @@ UI не должен самостоятельно определять успе
- Не сообщать `Success`, если обязательный шаг завершился неуспешно.
- Не скрывать ошибку обязательного шага за успешным перезапуском Spooler.
- Ограничивать удаление файлов только ресурсами подсистемы печати.
- Для потенциально опасных изменений реестра сохранять исходное состояние перед будущей реализацией rollback.
- Каждый фиксер, изменяющий реестр, реализует `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`:

1. Через WinRM определяется интерактивный пользователь и его SID.
2. Администратор сохраняет HKCU этого пользователя через `Registry::HKEY_USERS\<SID>`; restore-скрипт хранит
уже разрешённый путь, поэтому откат возвращается в тот же профиль.
3. На целевом ПК создаётся временная задача `W-Fix-Interactive-<id>` с типом входа `Interactive` и уровнем
`Limited`. Пароль пользователя не запрашивается и не сохраняется; используется существующий токен сеанса.
4. Пользовательская часть выполняет `WScript.Network`/PrintUI, пишет UTF-8 журнал и подтверждает фактически
назначенный принтер. Код задачи и маркеры `[ERROR]` проверяются независимо.
5. Административные действия — исправление ACL и перезапуск Spooler — остаются в WinRM-контексте.
6. Временная задача и файлы удаляются в `finally`; при отмене выполняется дополнительная best-effort очистка.
`ExecutionTimeLimit` ограничивает процесс даже при обрыве управляющего соединения.

Удалённый пользовательский фикс требует включённых WinRM и Task Scheduler, административного доступа и
уже вошедшего пользователя. Если интерактивного сеанса нет, операция завершается явной ошибкой — W-Fix не
сообщает ложный успех для HKCU администратора.

## Следующий архитектурный этап

Вынести создание сервисов из `MainWindowViewModel` в composition root и ввести интерфейсы исполнителя,
обнаружения принтеров и диалогов. Это позволит тестировать фиксеры без реального изменения Windows и добавить
режим предварительного просмотра/отката системных настроек.
интеграционные проверки снимка/отката на изолированной тестовой машине.
3 changes: 3 additions & 0 deletions src/W-Fix.App/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
<TextBlock Text="{Binding AdStatusText}" Foreground="#58A6FF" VerticalAlignment="Center" FontSize="12"/>
<Button Content="📝 Логи" Command="{Binding OpenLogsFolderCommand}" ToolTip="Открыть папку с текстовыми логами"
Style="{StaticResource FixButton}" Padding="10,6" Margin="8,0,0,0"/>
<Button Content="↩ Откат" Command="{Binding RestoreLastBackupCommand}"
ToolTip="Восстановить состояние до последнего исправления"
Style="{StaticResource FixButton}" Padding="10,6" Margin="8,0,0,0"/>
<Button Content="🔄 Обновить" Command="{Binding RefreshPrintersCommand}"
Style="{StaticResource FixButton}" Padding="10,6" Margin="8,0,0,0"/>
</StackPanel>
Expand Down
Loading