In today’s post, I thought I’d explore Printers via PowerShell a little.
- Have you ever needed to determine what printers where installed on a PC?
- Have you ever needed to determine the default printer on a PC?
- Have you ever needed to stop, or start, the print spooler?
All these things are easy to accomplish with PowerShell.
Note that the functions provided below rely on my PS_GetOutput() function which is part of my post VBA – Run PowerShell Command.
General Printer Information
To start off, I thought it would be nice to be able to simply list the various printers on a PC. In PowerShell we could do something like:
Get-Printer| Sort-Object Name| Select-Object Name, Location, DriverName, Type
Thus, we can build a VBA wrapper function and create:
Public Function PS_GetInstalledPrinters()
Dim sCmd As String
sCmd = "$printers = Get-Printer|" & _
"Sort-Object Name|" & _
"Select-Object Name, Location, DriverName, Type" & vbCrLf & _
"$combined = $printers | ForEach-Object { $_.Name + '--' + $_.Location + '--' + $_.DriverName + '--' + $_.Type }" & vbCrLf & _
"$result = $combined -join '~~'"
PS_GetInstalledPrinters = PS_GetOutput(sCmd)
End Function
and we could then use the above function by doing something like:
Function Test_Printers()
Dim sPrinter As String
Dim aPrinters() As String
Dim vPrinter As Variant
Dim aPrinter() As String
sPrinter = PS_GetInstalledPrinters()
aPrinters = Split(sPrinter, "~~")
Debug.Print "Printer Name", "Location", "Driver", "Type"
For Each vPrinter In aPrinters
aPrinter = Split(vPrinter, "--")
Debug.Print aPrinter(0), aPrinter(1), aPrinter(2), aPrinter(3)
Next vPrinter
End Function
wish will output similar to
Printer Name Location Driver Type Brother HL-2270DW series Printer http://192.168.0.105:80/WebServices/Device Brother HL-2270DW series Local Fax Microsoft Shared Fax Driver Local Microsoft Print to PDF Microsoft Print To PDF Local Microsoft XPS Document Writer Microsoft XPS Document Writer v4 Local OneNote for Windows 10 Microsoft Software Printer Driver Local
Default Printer Information
Now, let us explore getting the name and other information about the Default Printer.
Get the Default Printer’s Name
What about determining the name of the default printer? Nothing could be easier! For this, the PowerShell command looks like:
Get-CimInstance -Query "SELECT * FROM Win32_Printer WHERE Default=$true"
So, once again, we need only build a wrapper function, something like:
Public Function PS_GetDefaultPrinterName()
Dim sCmd As String
sCmd = "(Get-CimInstance -Query """"""SELECT * FROM Win32_Printer WHERE Default=$true"""""").Name"
PS_GetDefaultPrinterName = Replace(PS_GetOutput(sCmd), vbNewLine, "")
End Function
Now, with a single line of code you can retrieve the Default Printer’s name.
? PS_GetDefaultPrinterName
which returns something like
Microsoft Print to PDF
Note, that in this instance, since this is entirely done via a WMI call, we could bypass using PowerShell and use VBA to directly perform the WMI query. This would be faster. For instance, we could do something like:
Public Function WMI_GetDefaultPrinterName() As String
On Error GoTo Error_Handler
Dim oWMI As Object 'SWbemServicesEx 'WMI object to query about the PC's OS
Dim sWMIQuery As String 'WMI Query
Dim oCols As Object 'SWbemServicesObjectSet
Dim oCol As Object 'SWbemObjectEx
Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
sWMIQuery = "SELECT * FROM Win32_Printer WHERE Default=True"
Set oCols = oWMI.ExecQuery(sWMIQuery)
WMI_GetDefaultPrinterName = oCols.ItemIndex(0).Properties_("Name")
Error_Handler_Exit:
On Error Resume Next
Set oCols = Nothing
Set oWMI = Nothing
Exit Function
Error_Handler:
If Err.Number = -2147217385 Then
'Invalid query - Property doesn't exist
Else
MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: WMI_GetDefaultPrinterName" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occurred!"
End If
Resume Error_Handler_Exit
End Function
and then call it by doing:
? WMI_GetDefaultPrinterName
which returns the same value as with the PowerShell approach:
Microsoft Print to PDF
Get More Information About the Default Printer
To get general information about the default printer, not just its name, we need to combine 2 PowerShell commands and that would look something like:
Get-Printer -Name (Get-CimInstance -Query "SELECT * FROM Win32_Printer WHERE Default=$true").Name
Notice we use the command to get the default printer’s name and pass it to the Get-Printer CmdLet as the Name of the printer we want information about.
Now, we build our wrapper function, which should look like (pay attention to the quotes!):
Public Function PS_GetDefaultPrinterInfo()
Dim sCmd As String
sCmd = "Get-Printer -Name (Get-CimInstance -Query """"""SELECT * FROM Win32_Printer WHERE Default=$true"""""").Name|" & _
"Select-Object Name, Location, DriverName, Type|" & vbCrLf & _
"ForEach-Object { $_.Name + '--' + $_.Location + '--' + $_.DriverName + '--' + $_.Type }"
PS_GetDefaultPrinterInfo = PS_GetOutput(sCmd)
End Function
and then we can use it by doing something along the lines of:
Function Test_DefaultPrinter()
Dim sPrinter As String
Dim aPrinter() As String
sPrinter = PS_GetDefaultPrinterInfo()
aPrinter = Split(sPrinter, "--")
Debug.Print "Printer Name", "Location", "Driver", "Type"
Debug.Print aPrinter(0), aPrinter(1), aPrinter(2), aPrinter(3)
End Function
which will result in something similar to:
Printer Name Location Driver Type Microsoft Print to PDF Microsoft Print To PDF Local
Changing the Default Printer
PowerShell makes it extremely easy to change the default printer and it can be done with the following command:
(Get-WmiObject -class Win32_Printer|Where {$_.Name -eq 'YourPrinterNameGoesHere'}).SetDefaultPrinter()
Thus, we create a simple VBA wrapper for the command, giving us:
Public Function PS_SetDefaultPrinter(ByVal sPrinterName As String)
Dim sCmd As String
'We could first validate the printer actually exists on this PC!
sCmd = "(Get-WmiObject -class Win32_Printer|Where {$_.Name -eq '" & sPrinterName & "'}).SetDefaultPrinter()"
PS_Execute (sCmd)
End Function
Now, we can change the default printer of a PC by simply doing
Call PS_SetDefaultPrinter("Microsoft XPS Document Writer")
Call PS_SetDefaultPrinter("Microsoft Print to PDF")
etc…
A Few Resources on the Subject
- VBA – Run PowerShell Command
- Get-Printer (PrintManagement) | Microsoft Docs
- Sort-Object (Microsoft.PowerShell.Utility) – PowerShell | Microsoft Docs
- Select-Object (Microsoft.PowerShell.Utility) – PowerShell | Microsoft Docs
- ForEach-Object (Microsoft.PowerShell.Core) – PowerShell | Microsoft Docs
- Get-CimInstance (CimCmdlets) – PowerShell | Microsoft Docs