feat(04-01): implement script_generator with install.ps1.j2 template
- Jinja2 Environment with FileSystemLoader, trim_blocks, lstrip_blocks - render_install() with _duplex_map (LongEdge->TwoSidedLongEdge, ShortEdge->TwoSidedShortEdge) - install.ps1.j2: WOW64 guard as first block (SCRPT-05) - install.ps1.j2: SYSTEM/admin detection + UAC self-elevation (SCRPT-04) - install.ps1.j2: pnputil two-step driver staging + Add-PrinterDriver (SCRPT-01) - install.ps1.j2: idempotent port creation (Get-PrinterPort check) - install.ps1.j2: idempotent printer creation (Get-Printer check) - install.ps1.j2: Set-PrintConfiguration with duplex/color/paper/collate - All 7 unit tests pass
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
"""Script generator module — renders PowerShell scripts from Jinja2 templates.
|
||||
|
||||
Provides render_install() which produces a complete PowerShell install script
|
||||
containing WOW64 guard, UAC self-elevation, pnputil two-step driver staging,
|
||||
idempotent port/printer creation, and Set-PrintConfiguration with duplex mapping.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).parent.parent / "templates" / "scripts"
|
||||
|
||||
_env = Environment(
|
||||
loader=FileSystemLoader(str(_SCRIPTS_DIR)),
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
keep_trailing_newline=True,
|
||||
)
|
||||
|
||||
_duplex_map = {
|
||||
"OneSided": "OneSided",
|
||||
"LongEdge": "TwoSidedLongEdge",
|
||||
"ShortEdge": "TwoSidedShortEdge",
|
||||
}
|
||||
|
||||
|
||||
def render_install(
|
||||
printer_name: str,
|
||||
ip_address: str,
|
||||
port_name: str,
|
||||
driver_name: str,
|
||||
inf_filename: str,
|
||||
duplex_mode: str,
|
||||
color_mode: bool,
|
||||
paper_size: str,
|
||||
collate: bool,
|
||||
) -> str:
|
||||
"""Render install.ps1.j2 with the given printer configuration.
|
||||
|
||||
Args:
|
||||
printer_name: Display name of the printer.
|
||||
ip_address: IP address for the printer TCP/IP port.
|
||||
port_name: Port name (e.g. "IP_192.168.1.10").
|
||||
driver_name: Exact driver name as registered in Windows.
|
||||
inf_filename: INF filename inside the drivers/ subfolder.
|
||||
duplex_mode: One of "OneSided", "LongEdge", "ShortEdge" (model values).
|
||||
color_mode: True for color printing, False for mono.
|
||||
paper_size: Paper size string (e.g. "A4", "Letter").
|
||||
collate: True to enable collation.
|
||||
|
||||
Returns:
|
||||
Rendered PowerShell script as a string.
|
||||
"""
|
||||
tpl = _env.get_template("install.ps1.j2")
|
||||
return tpl.render(
|
||||
printer_name=printer_name,
|
||||
ip_address=ip_address,
|
||||
port_name=port_name,
|
||||
driver_name=driver_name,
|
||||
inf_filename=inf_filename,
|
||||
duplex_mode=_duplex_map.get(duplex_mode, duplex_mode),
|
||||
color=str(color_mode).lower(),
|
||||
paper_size=paper_size,
|
||||
collate=str(collate).lower(),
|
||||
)
|
||||
@@ -0,0 +1,67 @@
|
||||
# Generated by ImpTune — Printer: {{ printer_name }}
|
||||
# Install command: powershell.exe -NoProfile -ExecutionPolicy Bypass -File "install.ps1"
|
||||
#
|
||||
# This script installs the printer "{{ printer_name }}" via Intune Win32 app deployment.
|
||||
# It must be launched with -File (not -Command) so $PSScriptRoot is populated.
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# WOW64 Guard — relaunch in 64-bit PowerShell if running under WOW64 (Intune
|
||||
# runs Win32 app scripts in a 32-bit process; pnputil is 64-bit only).
|
||||
# This block MUST be the first executable code in the script.
|
||||
# ---------------------------------------------------------------------------
|
||||
if ($env:PROCESSOR_ARCHITECTURE -eq "x86" -and $env:PROCESSOR_ARCHITEW6432) {
|
||||
$ps64 = "$env:WINDIR\SysNative\WindowsPowerShell\v1.0\powershell.exe"
|
||||
& $ps64 -NoProfile -ExecutionPolicy Bypass -File "$PSCommandPath" @args
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SYSTEM vs User context detection + UAC self-elevation
|
||||
# Skip elevation when already running as SYSTEM (Intune MDM context).
|
||||
# ---------------------------------------------------------------------------
|
||||
$id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$isSystem = $id.IsSystem
|
||||
$isAdmin = ([System.Security.Principal.WindowsPrincipal]$id).IsInRole(
|
||||
[System.Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
|
||||
if (-not $isSystem -and -not $isAdmin) {
|
||||
Start-Process powershell.exe `
|
||||
-Verb Runas `
|
||||
-ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" `
|
||||
-Wait
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# pnputil two-step driver staging
|
||||
# Step 1: Stage INF + all associated files into Windows Driver Store
|
||||
# Step 2: Install the named driver from the Driver Store
|
||||
# ---------------------------------------------------------------------------
|
||||
pnputil.exe /add-driver "$PSScriptRoot\drivers\{{ inf_filename }}" /install
|
||||
|
||||
Add-PrinterDriver -Name "{{ driver_name }}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Idempotent port creation
|
||||
# ---------------------------------------------------------------------------
|
||||
if (-not (Get-PrinterPort -Name "{{ port_name }}" -ErrorAction SilentlyContinue)) {
|
||||
Add-PrinterPort -Name "{{ port_name }}" -PrinterHostAddress "{{ ip_address }}"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Idempotent printer creation
|
||||
# ---------------------------------------------------------------------------
|
||||
if (-not (Get-Printer -Name "{{ printer_name }}" -ErrorAction SilentlyContinue)) {
|
||||
Add-Printer -Name "{{ printer_name }}" `
|
||||
-PortName "{{ port_name }}" `
|
||||
-DriverName "{{ driver_name }}"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Configure print settings
|
||||
# ---------------------------------------------------------------------------
|
||||
Set-PrintConfiguration -PrinterName "{{ printer_name }}" `
|
||||
-DuplexingMode {{ duplex_mode }} `
|
||||
-Color ${{ color }} `
|
||||
-PaperSize {{ paper_size }} `
|
||||
-Collate ${{ collate }}
|
||||
Reference in New Issue
Block a user