RMM Script: The Ghost Printer Purge or How to Exorcise Redirected Devices and Stuck Spoolers

Clear stuck print jobs, delete ghost redirected printers, and fix high CPU usage on terminal servers with this automated PowerShell purge script. Learn the mechanics of SPL and SHD files and how to keep your print spooler healthy.

RMM Script: The Ghost Printer Purge or How to Exorcise Redirected Devices and Stuck Spoolers

5 min. read


The Ticket: The RDS Slowdown

The helpdesk queue has a slow burn of tickets from the accounting team. They are logging into the remote desktop server, but their local printers are not mapping correctly. Upon investigating, the server's "Devices and Printers" menu takes five minutes to load and is filled with hundreds of offline "Redirected" printers from past sessions. Print jobs are hanging, and the print spooler is consuming a massive chunk of CPU. We need to perform a deep purge of the print subsystem without rebooting the production server.


Pre-Flight Check

  • Permissions: Local Administrator or NT AUTHORITY\SYSTEM (via RMM execution).
  • Tools: PowerShell 5.1+.
  • Impact: High. Stopping the spooler will immediately pause all active print jobs across the machine. Do not run this during a massive batch printing run.

The Solution

Do not attempt to right-click and delete hundreds of printers through the Windows GUI. It will freeze the explorer process. Run this PowerShell script to cleanly halt the engine, clear the garbage, and restart the service.

PowerShell

# --- 404 & More: Ghost Printer Purge ---

# 1. Admin Rights Check
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Write-Error "CRITICAL ERROR: Elevated privileges required."
    exit 1
}

$SpoolerPath = "$env:windir\System32\spool\PRINTERS"

# 2. Force Stop the Spooler
Write-Host "Stopping Print Spooler..."
Stop-Service -Name Spooler -Force
Start-Sleep -Seconds 3

# Safety catch: If the service is hung, kill the process directly
if ((Get-Service -Name Spooler).Status -ne 'Stopped') {
    Write-Host "Spooler hung. Force killing spoolsv.exe..."
    Stop-Process -Name spoolsv -Force -ErrorAction SilentlyContinue
    Start-Sleep -Seconds 2
}

# 3. Clear the physical print queues
Write-Host "Clearing stuck print jobs and shadow files..."
Remove-Item -Path "$SpoolerPath\*.*" -Force -Recurse -ErrorAction SilentlyContinue

# 4. Remove offline "Redirected" terminal printers
Write-Host "Removing offline Redirected Printers from registry..."
Get-Printer | Where-Object { $_.Name -like "*Redirected*" -and $_.PrinterStatus -eq "Offline" } | Remove-Printer -ErrorAction SilentlyContinue

# 5. Kickstart the heart
Write-Host "Starting Print Spooler..."
Start-Service -Name Spooler

Write-Host "SUCCESS: Print subsystem purged." -ForegroundColor Green

The "Why" (Root Cause)

Why do these ghost printers pile up? When a user connects via RDP with "Local Resources" enabled, Windows maps their local hardware to the server session. If that session drops ungracefully due to a network timeout or a forced disconnect, the operating system fails to execute its cleanup routine. The temporary registry keys and printer objects are left behind.

Over time, the Print Spooler service (spoolsv.exe) attempts to poll these dead objects. When you have hundreds of orphaned redirected printers, the spooler gets trapped in a polling loop, causing the CPU spikes and memory leaks that ultimately freeze the print queues for everyone else on the server.

Stuck jobs happen when a file is sent to the spooler, but the target port is dead or offline. The spooler locks the files and tries infinitely, preventing any subsequent jobs from processing.


Under the Hood (Technical Deep Dive)

Let us look at the C:\Windows\System32\spool\PRINTERS directory. When a user clicks print, Windows creates two files here:

  1. The .SPL file (Spool): This contains the actual raw drawing commands and print data (PCL or PostScript).
  2. The .SHD file (Shadow): This contains the metadata. It tells the spooler who submitted the job, which printer it belongs to, and what priority it holds.

If the spooler is running, these files are locked by the kernel. You cannot delete them. This is why the script mandates stopping the spooler service first. Once the service releases the locks, deleting these files instantly flushes the queue of all pending and stuck jobs.

The original guide mentioned removing "non-standard printer ports". Doing this via script is highly risky because it is easy to accidentally delete legitimate third-party software ports (like PDF creators or specialized label printers). The safest approach is utilizing the Get-Printer cmdlet to specifically target objects matching the "Redirected" naming convention that are already flagged as "Offline" by the OS.


RMM & Automation Tips

  • RDS Maintenance: Terminal Servers and RDS hosts are notorious for this issue. Deploy this script as a scheduled task via your RMM to run every Sunday at 3:00 AM. It keeps the printer list pristine and prevents Monday morning helpdesk calls.
  • Self-Healing CPU Monitor: Create an RMM alert monitoring spoolsv.exe. If the process consumes more than 80% CPU for ten consecutive minutes, trigger this purge script automatically as a self-healing action.

Troubleshooting & Edge Cases

  • Edge Case 1: The WSD Infection. If you are dealing with local workstations rather than a server, the ghost printers might not be "Redirected". Windows loves to automatically discover network printers using Web Services for Devices (WSD) and install them silently. When the printer IP changes, the old WSD port dies, leaving a ghost. You can disable this behavior via Group Policy at Computer Configuration > Administrative Templates > Network > Link-Layer Topology Discovery.
  • Edge Case 2: Deep Registry Corruption. If Remove-Printer fails and the ghost devices still show up in the Control Panel, the registry is deeply corrupted. You will have to manually delete the subkeys located at HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers and reboot the machine.