Automating Network Printer Deployment with Microsoft Intune, PowerShell and PrintBRM
Automating Network Printer Deployment with Microsoft Intune, PowerShell and PrintBRM
A practical approach to packaging, deploying and detecting network printers on Windows 11 devices
Deploying printers to Windows 11 devices managed by Microsoft Intune can be challenging, especially when the devices are Microsoft Entra joined and not joined to a traditional Active Directory domain.
This is a common scenario for Windows kiosk devices, where the device is managed entirely through Intune but still needs access to an organization's printers.
Two Common Approaches
1. Microsoft Universal Print
Universal Print provides a cloud-based printing solution where printers can be managed and assigned through Microsoft 365 and Intune. This can be a good option for organizations that want to move their printing infrastructure to the cloud.
2. Intune + PowerShell
If you already have network printers that can be reached directly over the network, you can deploy them directly to the Windows client using Intune and PowerShell. In this scenario, the client connects directly to the printer rather than through a traditional Windows Print Server:
This guide focuses on this second approach. It is especially useful for environments with a limited number of known network printers where you want to deploy the same printer configuration consistently to multiple Intune-managed Windows devices.
\\PRINTSERVER01\Reception. In that scenario, the client connects to the shared printer queue on the server, and additional considerations such as network connectivity, authentication and permissions apply.For the solution in this guide, we will use Windows Print Management, PrintBRM, PowerShell and Microsoft Intune Win32 apps.
The workflow:
Configure printer → Export printer → Package with PowerShell → Deploy with Intune → Verify printer
The goal is to create a deployment that is repeatable, logged and easy to troubleshoot.
What We Are Going to Build
The final Intune application will:
- Import the printer configuration
- Make sure the Print Spooler service is running
- Install the expected printer queues
- Verify that the printers were installed successfully
- Write a log for troubleshooting
- Allow Intune to detect the installation based on the actual printer queues
The deployment will run in System context, making it suitable for device-based deployments such as Windows kiosk devices.
🖨️ Example Environment: Four Departments With Unique Network Printers
The following sample printers are used only to demonstrate how Intune-based IP printer deployment works. Replace the models, names, drivers, and IP addresses with the values from your own environment.
| Location | Printer Model | Display Name | Driver | IP Address |
|---|---|---|---|---|
| City Library | Canon i-SENSYS MF655Cdw | Library-Color-01 | Canon UFR II Generic Driver | 10.30.5.41 |
| Contact Center | Brother HL-L8360CDW | CC-Mono-Fast-01 | Brother Universal Driver | 10.30.12.88 |
| IT Helpdesk | Epson WorkForce Pro WF-C5790 | IT-Print-Secure-01 | Epson Universal Print Driver | 10.30.30.22 |
| Social Services | Ricoh IM 350F | Social-Dept-Print-01 | Ricoh PCL6 Universal Driver | 10.30.45.17 |
Why Use PrintBRM?
Instead of manually creating every printer, port and driver configuration with PowerShell, we can configure the printers once on a reference Windows 11 device and export the configuration using Print Management.
The exported .printerExport file can then be imported on the target devices using PrintBrm.exe. This gives us a simple deployment workflow:
This approach is particularly useful for kiosk devices where the printer is known in advance and the device should receive its printer configuration automatically.
🖨️ Exporting Your Local Printers (Windows 11)
To prepare the printer package, start by exporting the printers from a clean Windows 11 reference device — this ensures consistent drivers and configuration across all Intune-managed clients.
- Open the Start Menu and search for Print Management.
- In the left navigation pane, expand:
Print Servers → YourDeviceName → Printers. Here you'll find all printers currently installed on the machine. - Right-click the device name (for example,
W11-Reference) and select Export printers to a file… - The export wizard will guide you through saving a
.printerExportfile. Only actual installed printers are included — Windows' built-in virtual printers (like Microsoft Print to PDF) are automatically excluded.
This export file contains: printer objects, ports, drivers, and configuration settings. It will later be imported on Intune-managed endpoints using your deployment script.
#requires -Version 5.1
$ErrorActionPreference = 'Stop'
Write-Host ""
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host " Printer BRM Export Tool" -ForegroundColor Cyan
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
# ------------------------------------------------------------
# 1. Locate PrintBRM.exe
# ------------------------------------------------------------
$PrintBrm = Join-Path $env:windir "System32\spool\tools\PrintBrm.exe"
Write-Host "Checking for PrintBRM.exe..." -ForegroundColor Yellow
if (-not (Test-Path -LiteralPath $PrintBrm)) {
Write-Host ""
Write-Host "ERROR: PrintBrm.exe was not found." -ForegroundColor Red
Write-Host ""
Write-Host "Expected location:" -ForegroundColor Yellow
Write-Host $PrintBrm
Write-Host ""
exit 1
}
Write-Host "PrintBRM found:" -ForegroundColor Green
Write-Host $PrintBrm
Write-Host ""
# ------------------------------------------------------------
# 2. Check Print Spooler
# ------------------------------------------------------------
Write-Host "Checking Print Spooler service..." -ForegroundColor Yellow
try {
$Spooler = Get-Service -Name Spooler -ErrorAction Stop
}
catch {
Write-Host ""
Write-Host "ERROR: Print Spooler service was not found." -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
exit 1
}
if ($Spooler.Status -ne 'Running') {
Write-Host "Print Spooler is not running." -ForegroundColor Yellow
Write-Host "Starting Print Spooler..." -ForegroundColor Yellow
try {
Start-Service -Name Spooler -ErrorAction Stop
$Spooler.WaitForStatus(
[System.ServiceProcess.ServiceControllerStatus]::Running,
[TimeSpan]::FromSeconds(15)
)
}
catch {
Write-Host ""
Write-Host "ERROR: Unable to start Print Spooler." -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
exit 1
}
}
Write-Host "Print Spooler is running." -ForegroundColor Green
Write-Host ""
# ------------------------------------------------------------
# 3. Get installed printers
# ------------------------------------------------------------
Write-Host "Scanning installed printers..." -ForegroundColor Yellow
try {
$printers = @(Get-Printer -ErrorAction Stop)
}
catch {
Write-Host ""
Write-Host "ERROR: Unable to retrieve printers." -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
exit 1
}
if ($printers.Count -eq 0) {
Write-Host ""
Write-Host "No printers found on this device." -ForegroundColor Red
exit 1
}
# ------------------------------------------------------------
# 4. Display printers
# ------------------------------------------------------------
Write-Host ""
Write-Host "Detected printers:" -ForegroundColor Green
Write-Host ""
for ($i = 0; $i -lt $printers.Count; $i++) {
$printer = $printers[$i]
Write-Host ("[{0}] {1}" -f ($i + 1), $printer.Name) -ForegroundColor White
Write-Host (" Driver : {0}" -f $printer.DriverName) -ForegroundColor DarkGray
Write-Host (" Port : {0}" -f $printer.PortName) -ForegroundColor DarkGray
try {
$port = Get-PrinterPort -Name $printer.PortName -ErrorAction SilentlyContinue
if ($port -and $port.PrinterHostAddress) {
Write-Host (" IP : {0}" -f $port.PrinterHostAddress) -ForegroundColor DarkGray
}
}
catch {
# Ignore port lookup errors
}
Write-Host ""
}
# ------------------------------------------------------------
# 5. Select printers
# ------------------------------------------------------------
$selection = Read-Host "Enter printer numbers you want to export (example: 1,2)"
if ([string]::IsNullOrWhiteSpace($selection)) {
Write-Host ""
Write-Host "No selection was made." -ForegroundColor Red
exit 1
}
$numbers = $selection -split ',' |
ForEach-Object { $_.Trim() } |
Where-Object { $_ -match '^\d+$' } |
ForEach-Object { [int]$_ }
$selected = foreach ($number in $numbers) {
if ($number -ge 1 -and $number -le $printers.Count) {
$printers[$number - 1]
}
else {
Write-Host "Ignoring invalid printer number: $number" -ForegroundColor DarkYellow
}
}
$selected = @($selected)
if ($selected.Count -eq 0) {
Write-Host ""
Write-Host "No valid printers selected." -ForegroundColor Red
exit 1
}
# ------------------------------------------------------------
# 6. Display selection
# ------------------------------------------------------------
Write-Host ""
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host " Selected printers" -ForegroundColor Green
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
foreach ($printer in $selected) {
Write-Host " - $($printer.Name)" -ForegroundColor White
}
Write-Host ""
# ------------------------------------------------------------
# 7. Prepare export folder
# ------------------------------------------------------------
$ExportFolder = "C:\PrinterInventory"
$ExportFile = Join-Path $ExportFolder "PrinterExport.printerExport"
if (-not (Test-Path -LiteralPath $ExportFolder)) {
Write-Host "Creating export folder..." -ForegroundColor Yellow
New-Item -Path $ExportFolder -ItemType Directory -Force | Out-Null
}
# ------------------------------------------------------------
# 8. Remove previous export
# ------------------------------------------------------------
if (Test-Path -LiteralPath $ExportFile) {
Write-Host "Removing previous export..." -ForegroundColor Yellow
Remove-Item -LiteralPath $ExportFile -Force
}
# ------------------------------------------------------------
# 9. Run PrintBRM
# ------------------------------------------------------------
Write-Host ""
Write-Host "Starting PrintBRM export..." -ForegroundColor Yellow
Write-Host ""
Write-Host "Export file:" -ForegroundColor Cyan
Write-Host $ExportFile -ForegroundColor White
Write-Host ""
Write-Host "Running command:" -ForegroundColor DarkGray
Write-Host "$PrintBrm -b -f `"$ExportFile`"" -ForegroundColor DarkGray
Write-Host ""
# IMPORTANT:
# Call PrintBRM directly instead of Start-Process.
# This allows us to see PrintBRM output and avoids
# argument/quoting problems.
try {
& $PrintBrm -b -f $ExportFile
$PrintBrmExitCode = $LASTEXITCODE
}
catch {
Write-Host ""
Write-Host "ERROR: PrintBRM failed to start." -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
exit 1
}
# ------------------------------------------------------------
# 10. Check exit code
# ------------------------------------------------------------
Write-Host ""
Write-Host "PrintBRM exit code: $PrintBrmExitCode" -ForegroundColor Cyan
if ($PrintBrmExitCode -ne 0) {
Write-Host ""
Write-Host "ERROR: PrintBRM export failed." -ForegroundColor Red
Write-Host ""
Write-Host "Exit code: $PrintBrmExitCode" -ForegroundColor Red
exit $PrintBrmExitCode
}
# ------------------------------------------------------------
# 11. Search for the export file
# ------------------------------------------------------------
Write-Host ""
Write-Host "Checking for exported file..." -ForegroundColor Yellow
if (Test-Path -LiteralPath $ExportFile) {
$File = Get-Item -LiteralPath $ExportFile
}
else {
# PrintBRM may have created the file in the current
# working directory. Search for it as a fallback.
$FileName = Split-Path -Path $ExportFile -Leaf
$PossibleFiles = @(
Get-ChildItem -Path "C:\PrinterInventory" -Filter $FileName -File -ErrorAction SilentlyContinue
Get-ChildItem -Path (Get-Location).Path -Filter $FileName -File -ErrorAction SilentlyContinue
) | Sort-Object LastWriteTime -Descending
if ($PossibleFiles.Count -gt 0) {
$File = $PossibleFiles[0]
Write-Host ""
Write-Host "PrintBRM created the file here instead:" -ForegroundColor Yellow
Write-Host $File.FullName -ForegroundColor White
}
else {
Write-Host ""
Write-Host "ERROR: PrintBRM returned exit code 0," -ForegroundColor Red
Write-Host "but no .printerExport file could be found." -ForegroundColor Red
Write-Host ""
Write-Host "This is the PrintBRM output location that was requested:" -ForegroundColor Yellow
Write-Host $ExportFile
Write-Host ""
Write-Host "Please run this command manually to verify PrintBRM:" -ForegroundColor Yellow
Write-Host ""
Write-Host "`"$PrintBrm`" -b -f `"$ExportFile`"" -ForegroundColor White
Write-Host ""
exit 1
}
}
# ------------------------------------------------------------
# 12. Verify file size
# ------------------------------------------------------------
if ($File.Length -eq 0) {
Write-Host ""
Write-Host "ERROR: Export file exists but is empty." -ForegroundColor Red
exit 1
}
# ------------------------------------------------------------
# 13. Success
# ------------------------------------------------------------
Write-Host ""
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host " Printer export completed" -ForegroundColor Green
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Export file:" -ForegroundColor Yellow
Write-Host $File.FullName -ForegroundColor White
Write-Host ""
Write-Host "File size:" -ForegroundColor Yellow
Write-Host "$($File.Length) bytes" -ForegroundColor White
Write-Host ""
Write-Host "Selected printers:" -ForegroundColor Yellow
foreach ($printer in $selected) {
Write-Host " - $($printer.Name)" -ForegroundColor White
}
Write-Host ""
Write-Host "Export completed successfully." -ForegroundColor Green
Write-Host ""
Create the Intune Package
Create the following folder structure:
The PrinterDeployment folder contains all files required for the Intune Win32 package. The Intunewin folder is used as the output directory for the generated .intunewin file.
Install-Printers.ps1
Create Install-Printers.ps1 inside the PrinterDeployment folder:
#requires -Version 5.1
$ErrorActionPreference = 'Stop'
$ExportFileName = 'PrinterExport-2026.printerExport'
$WorkFolder = Join-Path $env:ProgramData 'Intune\PrinterDeployment'
$PackageExport = Join-Path $PSScriptRoot $ExportFileName
$LocalExport = Join-Path $WorkFolder $ExportFileName
$PrintBrm = Join-Path $env:windir 'System32\spool\tools\PrintBrm.exe'
# Create working directory
if (-not (Test-Path -LiteralPath $WorkFolder)) {
New-Item -Path $WorkFolder -ItemType Directory -Force | Out-Null
}
# Verify PrintBRM
if (-not (Test-Path -LiteralPath $PrintBrm)) {
Write-Error "PrintBRM was not found: $PrintBrm"
exit 1
}
# Verify printer export
if (-not (Test-Path -LiteralPath $PackageExport)) {
Write-Error "Printer export was not found: $PackageExport"
exit 1
}
# Make sure the Print Spooler is running
$Spooler = Get-Service -Name Spooler -ErrorAction Stop
if ($Spooler.Status -ne 'Running') {
Start-Service -Name Spooler -ErrorAction Stop
$Spooler.WaitForStatus(
[System.ServiceProcess.ServiceControllerStatus]::Running,
[TimeSpan]::FromSeconds(30)
)
}
# Copy the printer export locally
Copy-Item -LiteralPath $PackageExport -Destination $LocalExport -Force -ErrorAction Stop
# Restore the printer configuration
& $PrintBrm -r -f $LocalExport
$ExitCode = $LASTEXITCODE
# Check PrintBRM result
if ($ExitCode -ne 0) {
Write-Error "PrintBRM failed with exit code $ExitCode."
exit $ExitCode
}
Write-Output 'Printer deployment completed successfully.'
exit 0
Uninstall-Printers.ps1
Create Uninstall-Printers.ps1 inside the same folder:
#requires -Version 5.1
$ErrorActionPreference = 'Stop'
$ManagedPrinters = @(
'Printer_1st_floor'
'Printer_2nd_floor'
)
$WorkFolder = Join-Path $env:ProgramData 'Intune\PrinterDeployment'
# Remove managed printer queues
foreach ($PrinterName in $ManagedPrinters) {
$Printer = Get-Printer -Name $PrinterName -ErrorAction SilentlyContinue
if ($null -eq $Printer) {
continue
}
Remove-Printer -Name $PrinterName -Confirm:$false -ErrorAction Stop
}
# Remove the local printer export
$LocalExport = Join-Path $WorkFolder 'PrinterExport-2026.printerExport'
if (Test-Path -LiteralPath $LocalExport) {
Remove-Item -LiteralPath $LocalExport -Force
}
# Remove the working directory if it is empty
if (Test-Path -LiteralPath $WorkFolder) {
$RemainingFiles = Get-ChildItem -LiteralPath $WorkFolder -Force -ErrorAction SilentlyContinue
if ($RemainingFiles.Count -eq 0) {
Remove-Item -LiteralPath $WorkFolder -Force
}
}
Write-Output 'Printer removal completed successfully.'
exit 0
Detect-Printers.ps1
Create Detect-Printers.ps1 in the same folder. The detection script verifies that all printer queues managed by this package are installed:
#requires -Version 5.1
$RequiredPrinters = @(
'Printer_1st_floor'
'Printer_2nd_floor'
)
$InstalledPrinters = @(
Get-Printer -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty Name
)
$MissingPrinters = @(
$RequiredPrinters |
Where-Object { $_ -notin $InstalledPrinters }
)
if ($MissingPrinters.Count -eq 0) {
Write-Output 'All required printers are installed.'
exit 0
}
Write-Output 'The following printers are missing:'
foreach ($PrinterName in $MissingPrinters) {
Write-Output " - $PrinterName"
}
exit 1
Final Package Structure
After creating the scripts and copying the printer export, verify that the folder contains these four files:
Create the Win32 Package
Download the Win32 Content Prep Tool
Download Microsoft's Win32 Content Prep Tool and save IntuneWinAppUtil.exe on the packaging computer.
Run the Win32 Content Prep Tool
cd C:\Intune\Tools
.\IntuneWinAppUtil.exe
1. Source Folder
C:\Intune\Paketering\Print\packages\PrinterDeployment
2. Setup File
Install-Printers.ps1
3. Output Folder
C:\Intune\Paketering\Print\Intunewin
4. Catalog Folder
N
Verify the Package
Get-ChildItem "C:\Intune\Paketering\Print\Intunewin"
You should now have a structure similar to:
PrinterDeployment folder for future package updates.
🚀 Deploy the Win32 Printer Package in Microsoft Intune
Once your .intunewin package is ready, the final step is to publish it in Intune so devices can install the printers automatically or on-demand.
1Open Intune Admin Center
Sign in to intune.microsoft.com using an account that has permission to manage Windows applications.
Navigate to: Apps → Windows → Add
2Select the Win32 App Type
Under App type, choose Windows app (Win32). Click Select to continue.
3Upload Your .intunewin Package
Choose Select app package file. Browse to the file you created earlier:
Deploy_Printers.intunewin
Confirm the selection and proceed.
4Configure App Information
Provide the basic metadata:
- Application name
- Publisher
- Category
- Description
- Optional logo/icon
Click Next when ready.
5Define Install and Uninstall Commands
Use your PowerShell deployment scripts:
Install command:
powershell.exe -ExecutionPolicy Bypass -File Deploy_Printers.ps1
Uninstall command:
powershell.exe -ExecutionPolicy Bypass -File Remove_Printers.ps1
Set Install behavior to Device.
6Requirements
Specify the minimum OS version or architecture if needed. Most printer deployments work fine with default settings.
7Detection Rules
Choose Manually configure detection rules. Add a File rule and point it to the marker file your script creates, for example:
C:\ProgramData\Printerdeployment\
This ensures Intune can verify whether the printers are installed.
8Dependencies & Supersedence (Optional)
If you don't need them, simply skip these steps.
9Assign the Application
Choose how the app should be delivered:
- Available — users install via Company Portal
- Required — automatic installation on targeted devices
For testing, assign it to a small group — for example All users, or a specific device group (Library, Contact Center, Social Services).
10Create and Publish the App
Click Create. Intune will upload the package, process it, and make it available to assigned devices.
🧪 Testing the Deployment (Available vs Required)
The behavior on the client device depends on how you assigned the Win32 app in Intune. **For this lab, I assigned the application as Required rather than making it available through the Company Portal.**
If the app is Required
The installation will run automatically as soon as the device checks in with Intune. Once the installation completes, open Settings → Bluetooth & devices → Printers & scanners and you should see the printers that were defined.
If the app is Available
- Open Company Portal
- Find your Win32 app (for example, Deploy Printers)
- Select Install
🎉 Deployment complete. You now have a fully functional Intune-managed printer deployment pipeline. You can customize the app name and icon, offer printers as optional installs via Company Portal, or enforce automatic installation using Required assignments.











Kommentarer
Skicka en kommentar