Script to remove orphaned/stale printer objects

by Jeremy Saunders on July 29, 2008

I wrote this script to help a customer clean up old orphaned and stale printer objects from user profiles. This script can safely be executed in each user session and works a treat.

However, you may first want to try my script to remove printers the traditional way.

Here is the RemoveOrphanedPrinters.vbs script.


Option Explicit

' This script will remove registry keys and values. It was specifically written to clean out
' old orphaned/stale printer objects from a users registry hive that cannot be removed using
' the conventional methods.
' If any registry key or value contains the strings listed in the arrOrphanedPrinters array,
' it will be removed.

' This script could easily be modified to rename printer objects.

' Written by Jeremy@jhouseconsulting.com on 28th July 2008.

' Note that the RegValueExists and RegKeyExists functions were written by torgeir, a Microsoft
' MVP in Scripting and WMI. They were made freely available on the Internet.

Dim arrOrphanedPrinters, strComputer, strKeyRoot, strKeyPath, objRegistry, arrSubkeys
Dim strSubkey, return, BlnReturn

arrOrphanedPrinters = Array("iprint","printing")

Const HKEY_CURRENT_USER = &H80000001
strComputer = "."
Set objRegistry = GetObject("winmgmts:\\" & _
 strComputer & "\root\default:StdRegProv")

strKeyRoot = "HKCU\"
strKeyPath = "Printers\Connections"
If RegKeyExists(strKeyRoot & strKeyPath) Then
 return = objRegistry.EnumKey (HKEY_CURRENT_USER, strKeyPath, arrSubkeys)
 If return=0 and IsArray(arrSubkeys) Then
 For Each strSubkey In arrSubkeys
 BlnReturn=InArray(strSubkey,arrOrphanedPrinters)
 If BlnReturn Then
 DeleteSubkeys HKEY_CURRENT_USER, strKeyPath & "\" & strSubkey
 End If
 Next
 End If
End If

strKeyRoot = "HKCU\"
strKeyPath = "Printers\DevModePerUser"
If RegKeyExists(strKeyRoot & strKeyPath) Then
' wscript.echo strKeyRoot & strKeyPath & " exists."
 Call DeleteValues(strKeyRoot,strKeyPath)
End If

strKeyRoot = "HKCU\"
strKeyPath = "Printers\DevModes2"
If RegKeyExists(strKeyRoot & strKeyPath) Then
' wscript.echo strKeyRoot & strKeyPath & " exists."
 Call DeleteValues(strKeyRoot,strKeyPath)
End If

strKeyRoot = "HKCU\"
strKeyPath = "Printers\Settings"
If RegKeyExists(strKeyRoot & strKeyPath) Then
' wscript.echo strKeyRoot & strKeyPath & " exists."
 Call DeleteValues(strKeyRoot,strKeyPath)
End If

Set objRegistry = Nothing

wscript.quit(0)

Sub DeleteSubkeys(HKEY_CURRENT_USER, strKeyPath)
 Dim strComputer, objRegistry, arrSubkeys, strSubkey
 strComputer = "."
 Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
 objRegistry.EnumKey HKEY_CURRENT_USER, strKeyPath, arrSubkeys
 If IsArray(arrSubkeys) Then
 For Each strSubkey In arrSubkeys
 DeleteSubkeys HKEY_CURRENT_USER, strKeyPath & "\" & strSubkey
 Next
 End If
 objRegistry.DeleteKey HKEY_CURRENT_USER, strKeyPath
 Set objRegistry = Nothing
End Sub

Sub DeleteValues(strKeyRoot,strKeyPath)
 Dim strComputer, objRegistry, return, i, arrValueNames, arrValueTypes, BlnReturn
 strComputer = "."
 Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
 return = objRegistry.EnumValues (HKEY_CURRENT_USER, strKeyPath,_
 arrValueNames, arrValueTypes)
 If return=0 and IsArray(arrValueNames) Then
 For i=0 To UBound(arrValueNames)
 BlnReturn=InArray(arrValueNames(i),arrOrphanedPrinters)
 If BlnReturn Then
 objRegistry.DeleteValue HKEY_CURRENT_USER, strKeyPath, arrValueNames(i)
 End If
 Next
 End If
 Set objRegistry = Nothing
End Sub

Function RegValueExists(sRegValue)
' Returns True or False based of the existence of a registry value.
 Dim oShell, RegReadReturn
 Set oShell = CreateObject("WScript.Shell")
 RegValueExists = True ' init value
 On Error Resume Next
 RegReadReturn = oShell.RegRead(sRegValue)
 If Err.Number <> 0 Then
 RegValueExists = False
 End if
 On Error Goto 0
 Set oShell = Nothing
End Function

Function RegKeyExists(ByVal sRegKey)
' Returns True or False based on the existence of a registry key.
 Dim sDescription, oShell
 Set oShell = CreateObject("WScript.Shell")
 RegKeyExists = True
 sRegKey = Trim (sRegKey)
 If Not Right(sRegKey, 1) = "\" Then
 sRegKey = sRegKey & "\"
 End If
 On Error Resume Next
 oShell.RegRead "HKEYNotAKey\"
 sDescription = Replace(Err.Description, "HKEYNotAKey\", "")
 Err.Clear
 oShell.RegRead sRegKey
 RegKeyExists = sDescription <> Replace(Err.Description, sRegKey, "")
 On Error Goto 0
 Set oShell = Nothing
End Function

Function InArray(item,myarray)
 Dim i
 For i=0 To UBound(myarray) Step 1
 If instr(1,item,myarray(i),1) > 0 Then
 InArray=True
 Exit Function
 End If
 Next
 InArray=False
End Function

Enjoy!

Jeremy Saunders

Jeremy Saunders

Independent Consultant | Contractor | Microsoft & Citrix Specialist | Desktop Virtualization Specialist at J House Consulting
Jeremy is a highly respected, IT Professional, with over 30 years’ experience in the industry. He is an independent IT consultant providing expertise to enterprise, corporate, higher education and government clients. His skill set, high ethical standards, integrity, morals and attention to detail, coupled with his friendly nature and exceptional design and problem solving skills, makes him one of the most highly respected and sought after Microsoft and Citrix technical resources in Australia. His alignment with industry and vendor best practices puts him amongst the leaders of his field.
Jeremy Saunders
Jeremy Saunders
Jeremy Saunders
  • Pingback: J House Consulting / Script to remove printers()

  • I know this is an old post, but this script potentially does exactly what I need. However, running the script produces a “Memory is locked” error, citing line 66, character 3. The script is run against XP SP3 workstations. We need to remove printers from a test print server that were accidentally deployed in AD that are not removed by the more traditional RemovePrinterConnection function.

    • jeremy

      Hi William,

      Sorry for not responding earlier. I wrote this for a Citrix environment where it’s been used and tested many times on a Windows 2003 server. I have not tested it on a Windows XP workstation. However, from your description the “Memory is locked” error occurs when it tries to enumerate the registry using the EnumKey method and the array it is trying to return. There may be better ways to write this so that errors like these may be avoided. I will try and review it at some stage in the future. Just Googling shows that commenting out the Option Explicit statement and all the Dim statements helps. That’s not a good practice, but may help people overcome this issue until I’ve had time to re-write it.

      Cheers,
      Jeremy.

  • Captain Obvious

    I do not quite understand why you disassociate a local variable from its object right before you exit a procedure.

    • jeremy

      If you’re referring to “Set oShell = Nothing”, that’s a very old habit and allows us to explicitly clean up the objects in the right order before they go out of scope. In this function there is only one object, so it’s not a good example. However, if you had multiple objects and left it to the script engine to destroy them when they go out of scope, it may not do it in the desired order, and therefore destroy objects you’re relying on in other areas within the procedures. Some will argue that it’s unnecessary code. Others will argue that it’s a best practice.
      Cheers,
      Jeremy.

  • Kazys

    Jeremy, Thanks so much for this script. It is hard to detect orphaned printers using script. For any future wanderer, the error William experienced is resolved by adding a Dim in the DeleteSubkeys funciton. Like so.

    Sub DeleteSubkeys(HKEY_CURRENT_USER, strKeyPath)
    Dim arrSubkeys

    • Jeremy

      Hi Kazys,

      Thanks for the feedback and picking up that code error 🙂

      Cheers,
      Jeremy.

Previous post:

Next post: