Click an Ad

If you find this blog helpful, please support me by clicking an ad!

Tuesday, June 12, 2012

Powershell: Delete all networked printers (AND DRIVERS!)

Powershell: Delete all networked printers (AND DRIVERS!)


We've been moving a lot of printers around recently, and installing new ones. Our old printers were about 5 years old, and we drastically needed new ones. Let me tell you, the number one way to reduce helpdesk calls (after the initial rollout) is to install new printers that work well!!! We went with Xerox printers everywhere and are very happy so far (about a month in). The drivers are easy to use and stable.

We ran into some problems pushing out new drivers, and sometimes the easiest thing to do is just to delete all of the network printers and their drivers and then redeploy them. So I made this:

Filename: ResetNetworkPrinters.ps1
Author: Charles Stemaly

cd c:\
$PrnDrvrPathXP = "C:\Windows\system32\prndrvr.vbs"
$PrnDrvrPath7 = "C:\Windows\system32\Printing_Admin_Scripts\en-US\prndrvr.vbs"
$computerosversion = get-wmiobject -class Win32_OperatingSystem
# The location for the prndrvr.vbs script, which we will use to manipulate the drivers later, is in a different directory depending on the OS version, so we get the
# OS version of the computer and set variables for the different paths.

#Restart Print Spooler
(get-wmiobject -Class win32_service -filter "Name='Spooler'").stopservice()
sleep 5
(get-wmiobject -Class win32_service -filter "Name='Spooler'").startservice()
sleep 10
# I restart the print spooler. A lot. I haven't been able to figure out when I NEED to do this, and when I don't, so I just do it whenever I'm messing with something
# printer-related to ensure success.

$NetworkPrinters = ((Get-WmiObject -Class Win32_Printer) | where {$_.network -eq $true})
$DriverList = @()
# This section gets the list of all network printers, and initializes the driverlist array

Foreach ($Printer in $NetworkPrinters){
    $PrinterListing = ($Printer.name)
    #Write Driver name to array for later use
    $DriverList += $printer.drivername
    #Delete Printers
    Invoke-Expression "rundll32 printui.dll,PrintUIEntry /dn /q /n`"$PrinterListing`""
} #End Foreach
# We go through every network printer, append the drivername to the driverlist array, and then use Invoke-Expression to run a command that deleted the printer.
# I will talk more about Invoke-Expression later.

$DriverList = ($DriverList | Select-Object -Unique)
# This works through the driverlist array and removes any duplicate names

Foreach ($Driver in $DriverList){
    #Restart Print Spooler
    (get-wmiobject -Class win32_service -filter "Name='Spooler'").stopservice()
    sleep 2
    (get-wmiobject -Class win32_service -filter "Name='Spooler'").startservice()
    sleep 2
    #Delete Printer Drivers
    #-- FOR WINXP COMPUTERS
    IF ($computerosversion.version.startswith(5)) {
        Invoke-Expression "cscript $PrnDrvrPathXP -d -m `"$Driver`" -v 3 -e `"Windows NT x86`""
    } #End WinXP
    #-- FOR WIN7 COMPUTERS
    IF ($computerosversion.version.startswith(6)) {
        Invoke-Expression "cscript $PrnDrvrPath7 -d -m `"$Driver`" -v 3 -e `"Windows NT x86`""
    } #End Win7 If
} #End Foreach
# Here, for each driver, we restart the print spooler and then execute the appropriate command to remove the driver (which depends on the OS).

After this is all finished, we reboot the computer so that the drivers can be redeployed. I could have put that into the script, but we manually double-check that the printers are gone. My script works, but Windows is sometimes temperamental when it comes to printers.

Now, back to the Invoke-Expression command. At first, I was trying to call the prndrvr script by assigning it to a script variable, and then piping it back to me on the next line, like so:

$Script = "cscript $PrnDrvrPathXP -d -m `"$Driver`" -v 3 -e `"Windows NT x86`""
$Script

Unfortunately, Powershell doesn't just throw your string back onto the command line and then press enter. Powershell doesn't know that your string is an actual command. Hence the use of the Invok-Expression commandlet. That lets Powershell know to execute the string as a command.

Another thing I'd like to point out are the use of back ticks in the command. If I were to open a DOS command prompt and run this command, it would look like so:

C:\> cscript C:\Windows\system32\prndrvr.vbs -d -m "<drivername>" -v 3 -e "<environment>"

You can look at the actual syntax for using prndrvr.vbs here, but the backticks indicate that the double-quotes are actually part of the command itself (it's parameters technically). In short, if you have reserved characters showing up in your commands that you want treated as part of the string, you have to escape them so powershell just treats them as regular text characters.

4 comments:

  1. Thanks for the script. My two cents for Windows 10:

    Add after line 3 ($PrnDrvrPath7 =):
    $PrnDrvrPath10 = "C:\Windows\system32\Printing_Admin_Scripts\en-US\prndrvr.vbs"

    Add behind #End Win7 If:
    #-- FOR WIN10 COMPUTERS
    IF ($computerosversion.version.startswith(10)) {
    Invoke-Expression "cscript $PrnDrvrPath10 -d -m `"$Driver`" -v 3 -e `"Windows NT x86`""
    }
    #End Win10 If

    That should do the trick in Windows 10 :-)

    Time for a coffee ...

    ReplyDelete
    Replies
    1. Awesome man thank you for the Windows 10 help! :-)

      Delete
  2. The script ran without error but doesn't seem to have done anything. My printers are all still there.

    ReplyDelete
    Replies
    1. Correction... It worked great! Initially I was running as Admin. When I ran it under my own account it worked perfectly. Thanks!

      Delete