Adding a new vendor/series
This walks through adding a new driver package, using the layout
vendors/<vendor>/<series>/. Follow along with the existing
vendors/hp/upd-pcl6/ as a reference.
1. Identify the driver package
Find the vendor's redistributable driver archive (a .zip containing one or
more .inf files) and note:
- The download URL.
- The
.inffile that is the actual entry point (a driver archive often contains several.inffiles for different OS versions/architectures — pick the one matching Windows 10/11 x64). - The exact driver name string(s) the
.infregisters — look at its[<Manufacturer>.NTamd64...]section(s). Some vendors (HP) ship one universal name that works for every model; others (UTAX/Kyocera) bundle a universal name and hundreds of per-model names in the same package, where the model string you pass actually selects a different driver, not just metadata — see Supported Printers for both patterns and how the UTAX list was extracted from the INF itself. Check which kind you have before writingInstall.ps1.
2. Scaffold the folder
mkdir -p vendors/<vendor>/<series>/scripts
3. Pin the driver hash
nix develop
nix-prefetch-url --unpack <driver-url>
nix hash convert --hash-algo sha256 --to sri <hash-from-previous-command>
4. Write default.nix
Keep it minimal: fetch, unpack, call mkIntunePackage. See
vendors/hp/upd-pcl6/default.nix for the exact shape — src uses
fetchzip with the SRI hash from step 3, then
lib.mkIntunePackage { name = ...; driver = ...; scripts = ./scripts; }.
If the archive ships architectures/utilities you don't need (see
vendors/utax/kx-upd/default.nix, which prunes a ~200 MB download down to
the ~61 MB x64 driver tree), add a runCommand step that copies just the
subfolder you need before passing it through as driver.
Never commit lib.fakeHash — if you don't have the real hash yet, that's a
sign step 3 isn't done.
5. Write the scripts
scripts/Install.ps1 needs, at minimum:
- Parameters:
PrinterName(mandatory),IPAddress(mandatory),Model(optional; either purely informational, or — if this vendor bundles per-model driver names — the value that selects which one to install, falling back to the universal name when unset). - Dot-source
lib/common-scripts/TrustDriverPublisher.ps1(merged into every package's build tree automatically bymkIntunePackage.nix) and callImport-DriverPublisherTrust -InfPath $infPathright before staging. Without it, pnputil under SYSTEM fails with0xE0000242("publisher not trusted") for any signed third-party driver, because the interactive trust prompt Windows would otherwise show has no one to click it. - Idempotent driver staging (
pnputil.exe /add-driver ... /install, treating exit codes0/259/3010as success) and registration (Add-PrinterDriver). - Idempotent port (
Add-PrinterPort/Set-PrinterPort) and printer (Add-Printer/Set-Printer) creation — checkGet-*first, reconcile rather than fail if the resource already exists. - Logging to
C:\ProgramData\IntunePrinterPackages\logs. - Exit code
0on success, non-zero on failure.
scripts/Uninstall.ps1 mirrors it: remove the named printer, and remove its
port only if no other printer on the box still uses it. Never remove the
shared driver — other printers of the same series depend on it.
6. Register the package in flake.nix
Add one entry to vendorPackages:
"<vendor>-<series>" = pkgs.callPackage ./vendors/<vendor>/<series> { inherit mkIntunePackage; };
7. Build and sanity-check
nix build .#<vendor>-<series>
unzip -l result/<vendor>-<series>.intunewin # expect IntuneWinPackage/Contents/... and .../Metadata/Detection.xml
nix build .#all # confirm the aggregate still builds
8. Validate against a real Intune tenant
Upload the built .intunewin to a test Win32 app in Intune, install it on a
test device with a real or simulated printer at some IP, and confirm the
printer appears and the registry detection key
(HKLM\SYSTEM\CurrentControlSet\Control\Print\Printers\<PrinterName>) is
created. See
architecture.md#format-validation-and-fallback
if the upload or install fails in a way that points at the package format
itself rather than the driver/script logic.