Chapter 7
Managing Printing

Printing is a function of network infrastructure so basic to daily business operations that users just assume it is going to work the first time/every time. Meanwhile, IT pros have the challenge of making it so.

Although there has been no real change in the way users experience printing, its quality and speed have improved from the earliest days of the PC, when each application had its own set of printer drivers. The evolution of Windows has simplified printing significantly, although the printer server architecture in Windows Server 2019 is little changed from Windows Server 2012.

In Windows, the term printer refers to what is effectively a printer queue. Windows calls the physical printer a print device. When the application prints a document, it sends a print job to a print spooler. This spooler holds the individual print jobs, which may arrive faster than the print device can handle at any given time. The spooler then sends each print job to the printing device via a printer port, which can be either a physical port (such as LPT1:) or a network address.

With Windows Server 2019, the Print Services feature has three components.

  • Print server: This feature includes tools necessary to enable you to manage one or more print servers. It includes the Print Management MMC snap‐in.
  • Internet printing: This provides the ability to connect and print to shared printers using the Internet Printing protocol (IPP).
  • LPD service: This feature installs the Line Printer Daemon (LPD) service. Linux/Unix users can use the Line Printer Remote (LPR) service to use shared printers via the LPD host.

This chapter covers only the Print Server feature. Neither the LPD service nor the Internet Printing feature in Windows Server is used widely in today's networks.

In this chapter, you explore the following tasks:

Systems Used in This Chapter

This chapter uses two hosts.

  • DC1.Reskit.Org: This is a domain controller in the Reskit.Org domain that you created in Chapter 3, “Managing Active Directory.”
  • PSRV.Reskit.Org: This is a Windows Server 2019 host that is a member server in the Reskit.Org domain. In this chapter, you use this host and set it up as a print server.

This chapter also uses two networked printers, which you install using the chapter's scripts.

Figure 7.1 shows the systems (and printers) in use in this chapter.

Note that all systems used in this chapter need PowerShell 7 loaded before starting. You can do that manually, using the scripts from Chapter 1, or using the GitHub Gist at bit.ly/Pwsh-install-1 (or use the full URL shown in the introduction). Optionally, you can configure VS Code with the GitHub Gist at bit.ly/Pwsh-install-2 (or use the full URL shown in the introduction).

image

Figure 7.1: Systems used in this chapter

Installing and Sharing Printers

When you install Windows Server, the installation process sets up several printers on each system by default. These enable you to “print” to PDF or to Microsoft's XPS format. Adding applications can also add additional printers. For example, installing the Foxit PDF reader adds the entry Foxit Reader PDF Printer. Microsoft's Office product also installs a OneNote printer. These additional “printers” tend to be client‐side and print to the respective document types. If you want to print to paper, you need to install, configure, and deploy further physical printers.

Deploying a new print device involves several steps.

  1. Obtain and install the physical printer. You need to unpack it, turn it on, and connect it.
  2. Obtain the print drivers for the print device and install them on the print server. Windows ships with a large number of printer drivers, but you can find, download, and install additional ones. The example begins with this step.
  3. Configure a printer port to enable the print server to send data to the print device. This port is often a network address but can include printers attached physically to your print server.
  4. Install the printer in Windows. This creates the printer queue and associates the queue with a driver and port.
  5. Share the printer. You can share the printer to enable users to access it.

Before You Start

This section uses the PSRV host, a Windows 2019 server (installed with the full Desktop Experience), with no other features loaded. You should have installed PowerShell 7 on this server. This section makes use of Xerox printer drivers that you can download from the Internet. For the purposes of this chapter, you don't need an actual Xerox print device, as all you need are the driver files (although without the print device you are not going to see any physical output). If you have a different manufacturer's printer on your network, you may be able to modify the scripts to reflect your manufacturer and the driver URL(s) along with changes necessary to reflect how the drivers are packaged by the manufacturer.

Some printer manufacturers create installation programs that do the printer installation via a GUI. In that case, you could run the installation program on the printer server (for example, via RDP). Depending on the manufacturer and how it created the installation files, you may be able to install the drivers in a test machine and then extract the printer drivers and install them as shown here.

Installing the Print Server Feature on PSRV

You use the Install‐WindowsFeature command to install the Print Server feature and the associated management tools.

# 1. Install the Print-Server feature on PSRV plus tools
Import-Module -Name ServerManager -WarningAction SilentlyContinue
Install-WindowsFeature -Name Print-Server -IncludeManagementTools

You can see the output of this code in Figure 7.2.

image

Figure 7.2: Installing the Print Server feature

Creating a Folder for the Print Drivers

In preparation for installing a new printer, you need to create a temporary folder into which you can download the drivers. In this example, they are Xerox drivers. If you install printers from a different manufacturer, be sure to use an appropriate folder name.

# 2. Creating a folder for the Xerox printer drivers
$NIHT = @{
  Path        = 'C:\Xerox'
  ItemType    = 'Directory'
  Force       = $true
  ErrorAction = 'Silentlycontinue'
}
New-Item @NIHT | Out-Null

Downloading Printer Drivers

Different printing vendors provide their drives in a variety of channels. Xerox, for example, provides the drivers in a ZIP file that you can download using the Background Intelligent Transfer Service (BITS).

# 3. Downloading printer drivers for Xerox printers
$URL = '
http://bit.ly/XDrivers
'
$Target='C:\Xerox\XDrivers.zip'
Start-BitsTransfer -Source $URL -Destination $Target

In many cases, you may use a web browser to navigate to your printer manufacturer's web site and search for the drivers you need.

In this example, you use a compressed URL to save space. The full URL for the driver package is download.support.xerox.com/pub/drivers/6510/drivers/win10x64/ar/6510_5.617.7.0_PCL6_x64.zip.

Expanding the ZIP File

In the previous step, you downloaded a ZIP file. In this step, you extract the Xerox drivers to C:\Xerox\Drivers, as follows:

# 4. Expand the zip file
$Drivers = 'C:\Xerox\Drivers'
Expand-Archive -Path $Target -DestinationPath $Drivers

Installing the Drivers

Once you have expanded the driver package, you install the drivers it contains. This specific driver package contains drivers for two Xerox printer models (Phaser 6510 and Phaser 6515) using printui.dll.

# 5. Installing the drivers
$M1 = 'Xerox Phaser 6510 PCL6'
$P =  'C:\Xerox\Drivers\6510_5.617.7.0_PCL6_x64_Driver.inf\x3NSURX.inf'
rundll32.exe printui.dll,PrintUIEntry /ia /m "$M1"  /f "$P"
$M2 = 'Xerox WorkCentre 6515 PCL6'
rundll32.exe printui.dll,PrintUIEntry /ia /m "$M2"  /f "$P"

The Print Management module does not provide a command to add printer drivers. You can, however, use the functionality in printui.dll to add the printers. This DLL is part of the Print Manager GUI. This GUI's underlying tool, printmanagement.msc, uses the DLL to perform printer‐related administration. You use rundll32.exe to invoke the DLL, in this case to add drivers to the Windows driver store.

In some cases, you may find that these commands produce an error, calling rundll32.exe. If so, just rerun the command to resolve the issue.

The Xerox drivers you downloaded were contained in a ZIP file. Some printer drivers are built into Windows and do not require downloading. Other driver downloads may use other compression formats. Additionally, some drivers are delivered inside an installation program you run on the print server to install the drivers.

Adding a New Printer Port

In this example, the printer you are going to add is a networked printer. To enable the print spooler on PSRV to send data to the printer, you first define a new printer port.

# 6. Adding a new printer port
$PPHT = @{
  Name               = 'SalesPP'
  PrinterHostAddress = '10.10.10.61'
}
Add-PrinterPort @PPHT

In this case, you use the IP address 10.10.10.61. This is a hard‐coded address you assign for the networked printing device. If the printer gets its IP address details via DHCP, ensure you create a reservation. This simplifies adding a new printer on the print server.

Adding a New Printer

With the drivers installed and a printer port created, you can use the Add‐Printer command to add the printer to PSRV.

# 7. Adding a new printer
$PRHT = @{
  Name       = 'SalesPrinter1'
  DriverName = $M1
  PortName   = 'SalesPP'
}
Add-Printer @PRHT

Once this has completed, you should be able to print to the printer from PSRV.

Sharing the Printer

The steps thus far allow printing only from the print server. To enable users to access the printer remotely, you need to share it.

# 8. Sharing the printer
Set-Printer -Name SalesPrinter1 -Shared $True

Once you share a printer, users can begin to use it to print their documents. You can review the printer setup either using Net View \\PSRV (from an elevated PowerShell session) or using the printer commands.

Reviewing the Printer Configuration

The printer installation and configuration steps you have performed in this section produce no output. Once you have finished the installation of your new Xerox printer, you can use the relevant Get commands to review the printer port, printer driver, and printer settings, like this:

# 9. Review printer configuration
Get-PrinterPort -Name SalesPP |
    Format-Table -Autosize -Property Name, Description,
                           PrinterHostAddress, PortNumber
Get-PrinterDriver -Name Xerox* |
    Format-Table -Property Name, Manufacturer,
                           DriverVersion, PrinterEnvironment
Get-Printer -ComputerName PSRV -Name SalesPrinter1 |
    Format-Table -Property Name, ComputerName,
                           Type, PortName, Location, Shared

You can see the output of these commands in Figure 7.3.

image

Figure 7.3: Reviewing the setup of the new printer

In this section, you set up a new print server, created a printer port, and added/shared a new printer. Your printer is now available, and your users should be able to print to it.

Publishing a Printer in AD

Once you have a printer created and installed, you can also publish it to Active Directory. This helps your users find the printer. You can also specify a physical location for the printer to assist your users in finding the actual print device.

Once you publish the printer, your users can then search for published printers based on location, as well as on capabilities (such as color printers). In larger organizations this can be useful to enable users to find and use printers.

Before You Start

This example uses two hosts: PSRV and DC1. DC1 is a domain controller in the Reskit.Org domain. PSRV is a Windows 2019 server that you configured as a print server in “Installing and Sharing Printers.”

Getting the Printer Object

To publish a printer in AD, you first must create a printer object for the printer.

# 1. Get the printer object
Import-Module -Name PrintManagement -WarningAction SilentlyContinue
$Printer = Get-Printer -Name SalesPrinter1

PowerShell 7 does not natively support the Print Management module, but the commands in the module work via the Windows PowerShell compatibility mechanism discussed in Chapter 2, “PowerShell 7 Compatibility with Windows PowerShell.” By setting the ‐WarningAction parameter to SilentlyContinue, you avoid the warning message (warning that you are importing the module via the PowerShell compatibility mechanism).

Checking the Initial Publication Status

By default, printers are not published in AD. You can check the initial publication status by examining the printer object you just created.

# 2. Checking the initial publication status
$Printer | Format-Table -Property Name, Published

You can see, in the output in Figure 7.4, that the SalesPrinter1 printer is not currently shared in AD.

image

Figure 7.4: Checking on the SalesPrinter1 printer

Publishing the Printer to AD

Publishing a printer is straightforward. Before you publish the printer, you should use the Set‐Printer command to add a location to the printer information both held by PSRV and in AD, using the Set‐Printer command, like this:

# 3. Publish and share the printer to AD
$Printer | Set-Printer -Location '10th floor 10E4'
$Printer | Set-Printer -Published $true

This code configures your printer with a Location value and then publishes it in AD.

Viewing the Printer Publication Status

Having set the printer details, you can use Get‐Printer to observe the updated configuration.

# 4. View the updated publication status
Get-Printer -Name SalesPrinter1 |
    Format-Table -Property Name, Location, DriverName, Published

You can use the Get‐Printer command to view the key settings for your new printer, as shown in Figure 7.5.

image

Figure 7.5: Reviewing the setup of the new printer

As you can see, the Sales printer, SalesPrinter1, is now published to the AD.

Changing the Spool Folder

The Windows print spooler receives print jobs from printer users and sends the jobs to the print device. The print jobs that pass through the print server are stored temporarily in a spool folder on the print server. By default, Windows uses the folder $Env:SystemRoot\system32\spool\PRINTERS.

If you have a large print server handling a large number of printers, the potential size of this folder could become quite large. In turn, this could result in the system drive becoming full or full enough to affect the operation of your print server.

To avoid this issue, and as a best practice, you should move the spool file to another folder. This will allow you to keep your eye on the folder and possibly leverage Filesystem Resource Manager (FSRM) to generate reports on this folder. For a large print server, you might consider adding a disk to the server to hold the temporary spool files and updating the spool folder configuration to point to the new folder.

There are no PowerShell commands to enable you to change the spool folder. The .NET Framework includes the System.Printing.PrintServer class, which you use to set the spool folder location. By default, PowerShell does not load the System.Printing .NET namespace, which is necessary before you can change the spooler folder. Thus, you need to manually load the namespace and then use the classes to update the spool folder.

You can also configure the spool folder via the registry. Both methods work. The second method, via the registry, is probably a little faster than the first approach, but the difference is probably negligible in practice.

Before You Start

This section uses the printer server PSRV, which you created in “Installing and Sharing Printers.”

Loading the System.Printing Namespace

As mentioned, you need to add the System.Printing namespace explicitly to load the classes that this namespace contains into the current PowerShell session; you do that using the Add‐Type command.

# 1. Loading the System.Printing namespace and classes
Add-Type -AssemblyName System.Printing

Until you add this assembly, part of .NET Core, you cannot access the classes needed. If this assembly and the classes it contains are something you need to use on a regular basis, consider loading it as part of your PowerShell profile.

Displaying the Initial Spool Folder

Assuming you have not yet changed the configuration of the print server, you can use New‐Object to observe the current, and default, spool folder.

# 2. Displaying the initial spool folder
New-Object -TypeName System.Printing.PrintServer |
  Format-Table -Property Name, DefaultSpoolDirectory

The output from this code, shown in Figure 7.6, shows the default spool folder on the PSRV print server.

image

Figure 7.6: Reviewing existing spool folder

As you can see, the default spool folder is C:\Windows\system32\spool\PRINTERS.

Defining Required Permissions

To administrate the printer, you have to create a print server object using administrative permissions. To do that, you first create an object that states the required permissions.

# 3. Define the required permissions—that is, the ability to
#    administrate the server
$Permissions =
   [System.Printing.PrintSystemDesiredAccess]::AdministrateServer

Creating a Print Server Object

Next, you create a print server object with administrative permissions.

# 4. Create a PrintServer object with the required permissions
$NOHT = @{
  TypeName     = 'System.Printing.PrintServer'
  ArgumentList = $Permissions
}
$PS = New-Object @NOHT   # Print Server object (as admin)

Creating a New Spool Folder

To illustrate the effect of changing the spool folder, you can use New‐Item to create a new folder.

# 5. Create a new spool folder
$SP = 'C:\SpoolPath'
$NIHT = @{
  Path        = $SP
  ItemType    = 'Directory'
  Force       = $true
  ErrorAction = 'SilentlyContinue'
}
New-Item @NIHT | Out-Null

Changing the Spool Folder Path

You can now change the default spool folder by updating the appropriate property on the $PS object.

# 6. Changing the spool folder path
$PS.DefaultSpoolDirectory = $SP

Committing the Change

The updated $PS object next needs to be committed to save the change.

# 7. Committing the change
$PS.Commit()

The print server object is in‐memory. To enable the Print Spooler service to use the updated settings, you need to commit the changed printer object as shown here.

Restarting the Spooler Service

Once you have updated the spool folder, use the Restart‐Service command to restart the print spooler service. The PSRV server now spools all subsequent print jobs to the new spool folder.

# 8. Restart the Spooler Service to use the new folder
Restart-Service -Name Spooler

Depending on your system, you may see some warning messages. As long as the service starts, the messages are benign.

Reviewing the Spooler Folder

Once you have restarted the spooler, users can now print jobs, and Windows spools the print jobs to the newly specified folder. You can view this new folder:

# 9. Reviewing the spooler folder
New-Object -TypeName System.Printing.PrintServer |
    Format-Table -Property Name, DefaultSpoolDirectory

As you can see in the output, shown in Figure 7.7, your new spool folder is now in operation.

image

Figure 7.7: Reviewing the spool folder

Note that if there were unprinted printer jobs in the older spool folder, changing the folder name does not move those documents. You should ensure that the existing spool folder is empty before changing the spool folder.

Creating Another Spool Folder

As mentioned, there are two mechanisms for modifying the spooler folder, and you've just explored the first of them, using the System.Printing.PrintServer class. To demonstrate the second mechanism, using the registry, you need to create another new folder in the filesystem.

# 10. Creating a new/different spool folder
$SPL = 'C:\SpoolViaRegistry'  # different spool folder
$NIHT2 = @{
  Path        = $SPL
  Itemtype    = 'Directory'
  ErrorAction = 'SilentlyContinue'
}
New-Item  @NIHT2 | Out-Null

Stopping the Spooler Service

Before updating the registry, use Stop‐Service to stop the spooler service.

# 11. Stopping the Spooler service
Stop-Service -Name Spooler
 

Configuring the New Spool Folder

Next, you update the appropriate registry value to configure the new printer spool folder, with Set‐ItemProperty.

# 12. Configure the new spooler folder
$RPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Print\Printers'
$IP = @{
  Path    = $RPath
  Name    = 'DefaultSpoolDirectory'
  Value   = $SPL
}
Set-ItemProperty @IP

Restarting the Spooler

To complete the configuration of a new spool folder, you restart the spooler service.

# 13. Restarting the Spooler
Start-Service -Name Spooler

Viewing the Results

As you did previously, you can now review the updated spool directory by viewing the .NET PrintServer object.

# 14. Viewing the results
New-Object -TypeName System.Printing.PrintServer |
    Format-Table -Property Name, DefaultSpoolDirectory

As you can see in the output, shown in Figure 7.8, PSRV is now using the new spooler folder ( C:\SpoolViaRegistry).

image

Figure 7.8: Reviewing the spool folder after the change

Printing a Test Page

After deploying a new printer or after changing printer consumables, it can be useful to print a test page. A test page shows that the printer and print server are working and demonstrates the quality of printing performed by the print device.

There is no PowerShell command support for creating a printer test page. However, Windows Management Instrumentation (WMI) provides a mechanism to print a test page.

WMI, discussed in more detail in Chapter 9, provides the IT professional with a great wealth of information via the hundreds of available classes. On a Windows system, the WMI class WIN32_Printer contains a WMI object for each printer in the system. This WMI object contains a method, PrintTestPage, that you use here to generate a test page.

Before You Start

This section uses the printer server PSRV, which you created in “Installing and Sharing Printers.”

Getting Printer Objects from WMI

You retrieve the printers defined on this system by using WMI (and the Get‐CimInstance command).

# 1. Get printer objects from WMI
$Printers = Get-CimInstance -ClassName Win32_Printer

This command returns an array of printer objects—one for each printer defined in the system. The command returns the same printers and the same number of printers you would see calling Get‐Printer.

PowerShell 7 (and Windows PowerShell) uses a feature known as cmdlet definition over XML, which enables PowerShell to create commands based on WMI classes, combined with a small amount of XML. This incredibly useful technology enabled Microsoft to create a large number of new commands without a huge amount of effort. These commands, defined by XML contained in CDXML files, act just like cmdlets written in C#. The commands in the Print Management module are implemented using this technology.

The developers of the Print Management module chose which underlying properties and methods to expose. Not all the WMI printer object properties are exposed in the objects produced by Get‐Printer. Also, there is no cmdlet to create a printer test page even though the underlying WMI class does provide a method to do that. You use that method in this section to create a test page.

Displaying the Number of Printers Defined

You can view the number of printers available on PSRV.

# 2. Display the number of printers defined on PSRV
'{0} Printers defined on this system' -f $Printers.Count

The output of this code, in Figure 7.9, shows seven printers defined on PSRV.

image

Figure 7.9: Displaying the number of printers

Getting the Sales Group Printer WMI Object

To print a test page, you first have to obtain the WMI object representing the SalesPrinter1 printer, by using Where‐Object.

# 3. Get the Sales Group printer WMI object
$Printer = $Printers |
  Where-Object Name -eq 'SalesPrinter1'

Display the Printer's Details

To view the printer's details, you can display the $Printer object.

# 4. Display the printer's details
$Printer | Format-Table -AutoSize

You can view the output of this command in Figure 7.10.

image

Figure 7.10: Displaying the printer's details

Printing a Test Page

To print the printer test page, you invoke the PrintTestPage method.

# 5. Printing a test page
Invoke-CimMethod -InputObject $Printer -MethodName PrintTestPage

WMI objects can contain methods, which are commands that act on the underlying WMI object (or WMI class). You invoke these methods using the Invoke‐CimMethod cmdlet. In this case, the printer object has a method, PrintTestPage, which creates a test page and sends it to the printer. Invoking the method produces some basic output, which you can see Figure 7.11 (in addition to printing the test page).

image

Figure 7.11: Printing a test page

In the output shown in Figure 7.11, the CIM method produces a ReturnValue of 0. This indicates the WMI method was successful. Of course, the actual test page output as rendered by the print device is the ultimate test. WMI might work successfully, but the printer might have issues preventing it from printing properly. To view the details of the print jobs waiting to be printed, including test pages, you can use the Print Manager GUI, printmanagement.msc.

Creating a Printer Pool

In Windows, a printer pool is a single printer associated with two or more printing devices (each of which is assigned to a different printer port). This can be useful in environments that generate a lot of printed output, for example a large legal practice printing lots of long documents.

This is one of those rare cases where there are no existing commands, WMI classes, or .NET classes that enable you to create a printer pool directly. However, the printui.dll library (added to the PSRV system when you added the print server feature) contains functionality to create the printer pool. You used this DLL to add a printer driver in “Installing and Sharing Printers.”

Before You Start

This section uses the printer server PSRV, which you created in “Installing and Sharing Printers.”

Adding a Printer Port

To create a printer pool, you need at least two print devices attached via different printer ports. You created the first port in “Installing and Sharing Printers” and now need to create a second port.

# 1. Add a printer port for the printer
$P   = 'SalesPrinter1'   # printer name
$PP2 = 'SalesPP2'        # new printer port name
Add-PrinterPort -Name $PP2 -PrinterHostAddress 10.10.10.62

Creating the Printer Pool for SalesPrinter1

To create the printer pool, you call printui.dll and tell it the printer and which ports to use.

# 2. Creating the printer pool for SalesPrinter1
$PP1='SalesPP'   # first port name
rundll32.exe printui.dll,PrintUIEntry /Xs /n $P Portname $P1,$P2
 

This code sets up a printer pool. The printer SalesPrinter1 is now served by two ports and two printing devices.

The rundll32.exe program runs the print utility DLL. In effect, rundll pretends to be the Printer Management GUI that uses the DLL to carry out some action. RunDLL allows you to pass parameters to the DLL and get the DLL to do things, such as creating a printer port.

For more details on how to use rundll32 with printui.dll, see docs.microsoft.com/en-us/windows-server/administration/windows-commands/rundll32-printui.

Viewing Resulting Details

You can view the details for this printer using Get‐Printer.

# 3. Viewing resultant details
Get-Printer $P |
   Format-Table -Property Name, Type, DriverName, 
      PortName, Shared, Published

In the output of this code, shown in Figure 7.12, you can see that the SalesPrinter1 printer now has two ports associated and is set up in a printer pool.

image

Figure 7.12: Viewing printer pool details

Summary

In this chapter, you have worked with Windows printing, using PowerShell commands, WMI and .NET classes, and a Windows DLL.

You saw that the Printer Management module provided you the means to perform common printer‐related maintenance such as adding a printer. The module, however, does not provide commands for all the activities you might need to carry out, and therefore you need to use .NET objects and other command‐line tools.

This chapter illustrates well that where there are no PowerShell 7 or Window PowerShell commands to perform a task, you can often find other methods of automating your environment.