Script to remove orphaned/stale printer objects

by Jeremy 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.

Enjoy!


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)
  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
End Sub

Sub DeleteValues(strKeyRoot,strKeyPath)
  Dim i, arrValueNames, arrValueTypes, return, BlnReturn
  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
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(lcase(item),lcase(myarray(i))) Then
      InArray=True
      Exit Function
    End If
  Next
  InArray=False
End Function

No related posts.

{ 4 comments… read them below or add one }

William DiDomenico March 1, 2011 at 12:38 am

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.

Reply

jeremy December 1, 2011 at 8:18 am

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.

Reply

Captain Obvious December 1, 2011 at 6:45 am

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

Reply

jeremy December 1, 2011 at 7:31 am

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.

Reply

Leave a Comment

 

{ 1 trackback }

Previous post:

Next post: