Assigning a printer to a bay is useless if the bay cannot install it, and the fleet data says why that mattered: 42 of 44 printers could not resolve a driver. This is the delivery half - the drivers themselves, staged once per bay, so that creating a queue never waits on a download. Install-ShopdbPrinterDriver.ps1 does one driver: trust the package's signer, then pnputil /add-driver, then Add-PrinterDriver. Install-ShopdbPrinterDrivers.ps1 does a site's whole set from drivers.json, and answers a compliance question with -TestOnly, which is what makes it a clean DSC Script resource rather than a fire-and-forget install. Deliberately SEPARATE from assignment. Drivers are large, near-identical across a fleet and change rarely; assignments are small, per-bay and change often. Staging the set in the GE-Enforce common scope means the assignment client only ever creates a queue - it never fetches a 48 MB package while somebody is waiting to print, or discovers the share is unmounted at the worst moment. THE SIGNER TRUST STEP IS THE WHOLE TRICK, and it took a real driver to find it. certutil -addstore on the .cat file satisfied the Xerox package and failed every HP INF with "The publisher of an Authenticode(tm) signed catalog has not yet been established as trusted" - a coin toss, not a mechanism. The certificate is now extracted with Get-AuthenticodeSignature and added to Trusted Publishers, for every catalog under the package rather than the first INF's neighbours. On a locked bay there is no prompt to answer, so the old failure was silent. Verified on Windows against real packages, not by reading: all six drivers this site needs install through the script, a second run is a no-op, a wrong driver name fails with the names the package actually offers, and the DSC cycle behaves - TestOnly exits 1 on a clean box, install exits 0, TestOnly then exits 0. The packages themselves stay out of git: they are licensed vendor binaries, and they belong on the share beside the other imaging payloads. DEPLOYING-DRIVERS.md carries the GE-Enforce entry, the DSC configuration and the Intune shape, plus the constraint that has cost a session before: the SFLD share is mounted only during the enforcement cycle, so this runs as a manifest entry and never as its own scheduled task.
4.5 KiB
Deploying the printer driver set
The driver set is a package: Install-ShopdbPrinterDrivers.ps1, the
single-driver worker it wraps, a drivers.json naming each driver and where its
files are, and the driver packages themselves.
Staging drivers is deliberately SEPARATE from assigning printers. Drivers are large, change rarely and are identical across a fleet; assignments are small, per-bay and change often. Keeping them apart means creating a queue never waits on a download, and a driver never has to be fetched at the moment someone is trying to print.
The shape
ShopdbPrinterDrivers\
Install-ShopdbPrinterDrivers.ps1 the whole set, manifest driven
Install-ShopdbPrinterDriver.ps1 one driver (this does the work)
drivers.json what this site deploys
drivers\
hp_upd_ps\ xerox_gpd\ hp_designjet\ zebra_zt411\ ...
drivers.json paths may be relative to the package or absolute. A site whose
packages already live on a share points at the share and ships only the two
scripts and the manifest.
GE-Enforce, in the common scope
Every shop-floor PC gets every driver, once. After the first cycle each run is a
Get-PrinterDriver check per driver and nothing else, so the cost is a few
milliseconds, not a re-install.
{
"_comment": "Stage the site's printer drivers. Runs in-cycle because the share is only mounted then. Idempotent: a driver already present is skipped.",
"Name": "ShopDB printer drivers",
"Type": "PS1",
"Script": "scripts/Install-ShopdbPrinterDrivers.ps1",
"DetectionMethod": "Always"
}
It must be a manifest entry, not its own scheduled task. The SFLD share is mounted only for the duration of the enforcement cycle; off-cycle the paths simply do not exist and every run logs "package not found" forever.
Azure Machine Configuration / DSC
The script answers a compliance question, which is what makes it a clean Script
resource: -TestOnly reports whether every driver in the manifest is present and
exits 0 or 1 without changing anything.
Configuration ShopdbPrinterDrivers
{
Import-DscResource -ModuleName PSDesiredStateConfiguration
Node localhost
{
Script PrinterDrivers
{
GetScript = {
@{ Result = (Get-PrinterDriver | Select-Object -ExpandProperty Name) -join ', ' }
}
TestScript = {
$p = Start-Process -FilePath 'powershell.exe' -PassThru -Wait -WindowStyle Hidden `
-ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File',
'C:\ProgramData\ShopDB\Drivers\Install-ShopdbPrinterDrivers.ps1','-TestOnly'
return ($p.ExitCode -eq 0)
}
SetScript = {
Start-Process -FilePath 'powershell.exe' -Wait -WindowStyle Hidden `
-ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File',
'C:\ProgramData\ShopDB\Drivers\Install-ShopdbPrinterDrivers.ps1'
}
}
}
}
Deliver the package to C:\ProgramData\ShopDB\Drivers however that estate
already delivers files - a Win32 app, a File resource, or the imaging step.
Intune
Package the folder as a Win32 app.
- Install:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File Install-ShopdbPrinterDrivers.ps1 - Detection: a script running the same file with
-TestOnly, exit 0 = detected - Run as SYSTEM. Adding a printer driver has required administrator rights since the 2021 print hardening, and SYSTEM satisfies it.
Why not have the assignment client fetch drivers
It was considered and rejected. A bay would then download a driver at the moment
a printer is assigned, which is the worst time: someone is waiting, the share may
be unmounted, and a 48 MB package would be pulled per bay per change. Staging the
set in common makes assignment a queue creation and nothing more.
One driver per package, named exactly
drivers.json carries the driver name as its INF declares it - Add-PrinterDriver
matches that string and nothing else. The names verified on Windows for the
reference site's fleet:
| driver | covers |
|---|---|
HP Universal Printing PS |
HP office printers |
Xerox Global Print Driver PCL6 |
Xerox office printers |
HP DesignJet T1700dr V4 |
DesignJet plotters (a v4 class driver) |
ZDesigner ZT411-300dpi ZPL |
Zebra ZT411 labels |
EPSON TM-C3500 |
Epson ColorWorks labels |
DTC4500e Card Printer |
HID FARGO card printer |