--- phase: 04-script-generation plan: "01" subsystem: script-generator tags: [jinja2, powershell, tdd, wow64, uac, pnputil, idempotency] one_liner: "Jinja2-based install.ps1 generator with WOW64 guard, UAC elevation, pnputil two-step, and duplex mapping" dependency_graph: requires: [] provides: [render_install, install.ps1.j2] affects: [imptune.generators.script_generator, imptune.templates.scripts] tech_stack: added: [] patterns: - Jinja2 FileSystemLoader with trim_blocks + lstrip_blocks for PowerShell templates - Plain-string function parameters for DB-free unit testability - _duplex_map translation dict (model values -> PowerShell cmdlet values) key_files: created: - imptune/generators/script_generator.py - imptune/templates/scripts/install.ps1.j2 - tests/test_script_generator.py modified: [] decisions: - "render_install() takes plain string args (not ORM Printer object) — keeps tests DB-free" - "Boolean color_mode/collate converted to lowercase 'true'/'false' strings; template adds $ prefix" - "_duplex_map translates before rendering: LongEdge->TwoSidedLongEdge, ShortEdge->TwoSidedShortEdge" - "WOW64 guard comment avoids 'pnputil.exe' text to preserve ordering assertion in test" metrics: duration: "~2 min" completed_date: "2026-04-10" tasks_completed: 1 files_created: 3 files_modified: 0 tests_added: 7 tests_passing: 68 requirements-completed: [SCRPT-01, SCRPT-04, SCRPT-05] --- # Phase 4 Plan 01: Script Generator (Install) Summary **One-liner:** Jinja2-based install.ps1 generator with WOW64 guard, UAC elevation, pnputil two-step, and duplex mapping ## What Was Built A TDD-developed module `imptune/generators/script_generator.py` with a single public function `render_install()` that renders the `install.ps1.j2` Jinja2 template into a complete, production-ready PowerShell printer install script. ### render_install() function - Takes plain string arguments (no ORM dependency) for easy unit testing - Translates `duplex_mode` via `_duplex_map` before passing to template - Converts Python booleans to lowercase strings (`"true"`/`"false"`) for PowerShell `$true`/`$false` rendering ### install.ps1.j2 template structure (in order) 1. Header comment with printer name and required Intune install command 2. WOW64 guard (`$env:PROCESSOR_ARCHITECTURE` + `SysNative` relaunch) — FIRST executable block 3. SYSTEM vs admin detection (`[WindowsIdentity]::GetCurrent()`, `IsSystem`, `IsInRole(Administrator)`) + UAC self-elevation via `Start-Process -Verb Runas` 4. pnputil two-step: `/add-driver` to stage INF, then `Add-PrinterDriver` to register 5. Idempotent port creation: `Get-PrinterPort` check before `Add-PrinterPort` 6. Idempotent printer creation: `Get-Printer` check before `Add-Printer` 7. `Set-PrintConfiguration` with translated duplex, color, paper size, collate ## TDD Execution ### RED Phase (commit b4f2c64) 7 tests written in `tests/test_script_generator.py` covering SCRPT-01, SCRPT-04, SCRPT-05. All failed with `ModuleNotFoundError` (confirmed RED). ### GREEN Phase (commit 8193e9d) - `imptune/generators/script_generator.py` created - `imptune/templates/scripts/install.ps1.j2` created One auto-fix required during GREEN: template comment contained `"pnputil.exe"` before the WOW64 `PROCESSOR_ARCHITECTURE` check text, causing the ordering assertion in `test_render_install_wow64_guard` to fail. Fixed by removing `.exe` from the comment text. Not a logic error — purely a textual ordering issue in the rendered output. All 7 new tests pass. Full suite: 68/68 passing. ## Commits | Hash | Type | Description | |------|------|-------------| | b4f2c64 | test | RED phase — 7 failing tests for script_generator | | 8193e9d | feat | GREEN phase — script_generator.py + install.ps1.j2 | ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] Template comment contained 'pnputil.exe' before WOW64 guard text** - **Found during:** GREEN phase test run - **Issue:** Comment in the WOW64 guard block header said "pnputil.exe is 64-bit only", so the string "pnputil.exe" appeared in the rendered output before "PROCESSOR_ARCHITECTURE", breaking the ordering assertion in `test_render_install_wow64_guard` - **Fix:** Changed "pnputil.exe is 64-bit only" to "pnputil is 64-bit only" in the template comment - **Files modified:** `imptune/templates/scripts/install.ps1.j2` - **Commit:** 8193e9d (included in same GREEN commit) ## Self-Check: PASSED All created files verified on disk. All commits verified in git log. | Item | Status | |------|--------| | imptune/generators/script_generator.py | FOUND | | imptune/templates/scripts/install.ps1.j2 | FOUND | | tests/test_script_generator.py | FOUND | | Commit b4f2c64 (RED) | FOUND | | Commit 8193e9d (GREEN) | FOUND |