We help IT Professionals succeed at work.

VBScript to Kill print jobs

Medium Priority
2,570 Views
Last Modified: 2015-11-19

Hi,

I am trying to get a vbscript to run in the background and delete any print jobs spooled that are over 1hr old (on XP SP3 Machines)

I have this script that will successfully delete files older than 1hr

*******************
sFolder = "c:\windows\system32\spool\printers"
iMaxAge = 1
Set oFSO = CreateObject("Scripting.FileSystemObject")
If oFSO.FolderExists(sFolder) Then
for each oFile in oFSO.GetFolder(sFolder).Files
If DateDiff("h", oFile.DateLastModified, Now) > iMaxAge Then
oFile.Delete
End If
next
End If
**************************

and I have scripts that "should" stop and start the "print spooler" service


**************************

'stop spooler
strServiceName = "print spooler"
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='" & strServiceName & "'")
For Each objService in colListOfServices
    objService.StopService()

**************************
'start spooler
For Each objService in colListOfServices
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colListOfServices = objWMIService.ExecQuery ("Select * from Win32_Service Where Name ='" & strServiceName & "'")
    objService.StartService()
**************************


However I seem unable to stitch this togther so that the print spooler is only stopped if there are files over 1hour old, then the delete kicks in, then restart the service.

I do not want to stop the service unless there are files over 1hr old to delete.

Can anyone point me in the right direction why I cant seem to get this to work?

Thanks


Comment
Watch Question

Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
sorry to post complete untested but how about this:

blnFound = False
sFolder = "c:\windows\system32\spool\printers"
iMaxAge = 1
Set oFSO = CreateObject("Scripting.FileSystemObject")
If oFSO.FolderExists(sFolder) Then
  for each oFile in oFSO.GetFolder(sFolder).Files
    If DateDiff("h", oFile.DateLastModified, Now) > iMaxAge Then
      If not blnFound then ' first
        blnFound = True
        Call stopSrv
      End If
      oFile.Delete
    End If
  next
End If

If blnFound Then Call startSrv

Sub stopSrv 'stop spooler
  strServiceName = "print spooler"
  Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  For Each objService in colListOfServices
    objService.StopService()
  Next
End Sub

Sub startSrv 'start spooler
  Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colListOfServices = objWMIService.ExecQuery ("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  For Each objService in colListOfServices
    objService.StartService()
  Next
End Sub

Open in new window

Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
better to move "strServiceName = ..." to the start of the script I see now.
Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
with that last change at least the syntax seems ok but on my system it doesn't find the service so can't stop/start it...
JCIT2009Director

Author

Commented:
hi.... thanks for this.

I will try the script tomorrow and let you know how I get on.  I dont have any XP machines at home to try this on. In hindsight, I think the service should just be "spooler" - sorry I dont normally have to do things like this.
JCIT2009Director

Author

Commented:
Hi - managed to remote on to an XP box to try this and although the file delete was working on txt files it for some reason doesn't seem to work on the spooled print files. *scratches head*

However - I have taken your script and bodged it with some other script that does seem to delete the right files and have come up with this....

********************
blnFound = False
strServiceName = "spooler"
sdir="c:\windows\system32\spool\printers"
dim dt, fso, odir, f
dt=now
set fso=createobject("scripting.filesystemobject")
if fso.folderexists(sdir) then
set odir=fso.getfolder(sdir)
for each f in odir.files
if (datediff("n",f.datelastmodified,dt)>2) then
    If not blnFound then ' first
        blnFound = True
        Call stopSrv
     End If
End If
next
End If

If blnFound Then Call startSrv

Sub stopSrv 'stop spooler
    Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  For Each objService in colListOfServices
    objService.StopService()
  Next
f.delete true 'forced
End Sub

Sub startSrv 'start spooler
  Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colListOfServices = objWMIService.ExecQuery ("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  For Each objService in colListOfServices
    objService.StartService()
  Next
End Sub
set odir=nothing
set fso=nothing
************************

On first attempt, remotely, it seemed to work, but alas I have now been cut off and cant seem to get back on so will not be able to find out until tomorrow PM when I am back in the office (boring site meeting in the morning)
JCIT2009Director

Author

Commented:
*note

I have set it to 2mins in the above script for speed during testing
Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
In the above script only the first file will be deleted, the command "f.delete true" should be in the main loop, after the "if not found ... end if" block.
JCIT2009Director

Author

Commented:
With moving the f.delete as you suggest - it now seems to do whats needed.

I would never have got there without your help - Thank you
JCIT2009Director

Author

Commented:
hmm.... ok. now with further testing. If there are multiple files, but no files that meet the delete criteria I get permission denied error.  If there are file(s) to delete, it works fine.

I knew there was a reason I am not a programmer.


Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
can you post the current code please, just to check there's nothing out of place?
JCIT2009Director

Author

Commented:
Thanks again for looking at this for me...

The most successful code so far is below...but it only seems to work if there are files to delete, if not or if there are a mix of files to leave and files to delete, it fails with permission error?

**********************************
blnFound = False
strServiceName = "spooler"
sdir="c:\windows\system32\spool\printers"
dim dt, fso, odir, f
dt=now
set fso=createobject("scripting.filesystemobject")
if fso.folderexists(sdir) then
set odir=fso.getfolder(sdir)
for each f in odir.files
if (datediff("n",f.datelastmodified,dt)>2) then
    If not blnFound then ' first
        blnFound = True
        Call stopSrv
     End If
End If
f.delete true 'forced
next
End If

If blnFound Then Call startSrv

Sub stopSrv 'stop spooler
    Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  For Each objService in colListOfServices
    objService.StopService()
  Next

End Sub

Sub startSrv 'start spooler
  Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colListOfServices = objWMIService.ExecQuery ("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  For Each objService in colListOfServices
    objService.StartService()
  Next
End Sub
set odir=nothing
set fso=nothing
******************************************

 I have also tried the following, but this does not work at all.

****************************************
blnFound = False
strServiceName = "spooler"
sdir="c:\windows\system32\spool\printers"
dim dt, fso, odir, f
dt=now
set fso=createobject("scripting.filesystemobject")
if fso.folderexists(sdir) then
set odir=fso.getfolder(sdir)
for each f in odir.files
if (datediff("n",f.datelastmodified,dt)>2) then
    If not blnFound then ' first
        blnFound = True
        Call stopSrv
     End If
f.delete true 'forced
End If
next
End If

If blnFound Then Call startSrv

Sub stopSrv 'stop spooler
    Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  For Each objService in colListOfServices
    objService.StopService()
  Next

End Sub

Sub startSrv 'start spooler
  Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colListOfServices = objWMIService.ExecQuery ("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  For Each objService in colListOfServices
    objService.StartService()
  Next
End Sub
set odir=nothing
set fso=nothing
Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
Well, the first piece of code would try to delete all files, as the 'delete' is outside of the time checking "if - end if" block. The second piece of code should work, if it finds any files older than the specified time period and the user that's running the script has permission to delete files in the specified folder.

I'm wondering by the way if there wouldn't be a nicer way to do this, maybe a PowerShell script can do it similar to a cancel or delete in the printer queue?

Commented:
@JCIT2009

Are you still on this? I may have an idea, using a batch file.
Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
I must admit I haven't explored it further, partly because I can't test in the same situation as yours. I don't see the value of a batch file here. Would you like help finding out if there's a better way to do this, like using an API, either from PowerShell or maybe even something like a VB.NET application?

Commented:
@robert_schutt:
"I don't see the value of a batch file here"
I don't see why not! What if it works?
Anyway, let's first see if JCIT2009 is still on this, and I'll see if I can help.

Cheers
JCIT2009Director

Author

Commented:
Hi,

Sorry been away. I now have a different, but similar, working VBScript.  I will post it tomorrow in case anyone finds it useful.

Thanks for all the help.

JCIT2009
Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
@ReneGe: sorry, I read your post wrong; thought it was directed at me, from the asker. I read it as: "would a batch file be able to do something different than vbs" and I couldn't see what that would be. Like @JCIT2009, maybe you should just post your idea, it might help somebody who stumbles across this while searching for a solution later.

Commented:
@Robert:Don't worry :)

My idea was to scan the time of the printer spool files and delete from there.

Inspired by BillPrew's scripts found in:
http://www.experts-exchange.com/OS/Microsoft_Operating_Systems/Server/2003_Server/Q_27459125.html?cid=748#a37174758

And gerwinjansen:
http://www.experts-exchange.com/OS/Microsoft_Operating_Systems/MS_DOS/Q_27458652.html?cid=748#a37173619
I have not tested it but here is my idea.


@ECHO OFF
SETLOCAL EnableDelayedExpansion
SET SpoolerFolder=C:\Windows\System32\spool\PRINTERS

FOR /F "tokens=1-4 delims= " %%A IN ('WMIC Path Win32_LocalTime Get Day^,Month^,Year^,Hour ^| findstr /r [0123456789]')  DO (
   IF %%B LEQ 9 (SET hh=09) ELSE (SET hh=9)
   SET Now=%%D%%C%%A!hh!
)

NET STOP SPOOLER

FOR /R "%SpoolerFolder%" %%F in ("*.*") do (
   REM Adjust file name for WMIC call (replace \ with \\)
      SET WmicFile=%%~F
      SET WmicFile=!WmicFile:\=\\!
   REM Do WMIC call to get last modified date/time stamp for this file
      WMIC datafile where "name='!WmicFile!'" get lastmodified | FINDSTR %Now% >NUL || ECHO DEL /f /q %%~F
)

NET START SPOOLER
PAUSE
EXIT

Open in new window

Commented:
The flaw in my script will be that if a print job is sent at let's say 10:59 and the script runs at 11:00, that print job will also be deleted. I will gladly resolve this issue if it has a value, onless you (robert_schutt) feel like giving it a shot.

Cheers
Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
Great. No, go ahead. I didn't know what was preventing the vb script we got so far to do its job.

Commented:
@robert_schutt:
I don't know VBScript, so I can't help with this. Let's see what JCIT2009 found in [37184894].
JCIT2009Director

Author

Commented:
Hi Guys,

OK this is the end result - it works!!

Hope someone else finds this useful at some point as well.

:-)

--------------------------------------------------


Option Explicit

Dim blnFound, strServiceName, sdir, CurrentDateTime, fso, odir, f, GracePeriodMinuteCount

'//////////////////////////////////////////////////////////
'/ Variables
'//////////////////////////////////////////////////////////

strServiceName = "spooler"
sdir="c:\windows\system32\spool\printers"
CurrentDateTime = Now
GracePeriodMinuteCount = 30

blnFound = False

'//////////////////////////////////////////////////////////
'/ Main Code
'//////////////////////////////////////////////////////////


set fso=createobject("scripting.filesystemobject")

If fso.folderexists(sdir) then
Set odir=fso.getfolder(sdir)


On Error Resume Next
Err.Clear
If (odir.Files.Count > 0) Then
For each f in odir.Files

If Err <> 0 Then
MsgBox "Error Fetching Files in: " & sdir & " - " & Err.Description
Err.Clear
End If

On Error Resume Next
If (datediff("n",f.datelastmodified, CurrentDateTime) > GracePeriodMinuteCount) then

If Err <> 0 Then
MsgBox "Error Fetching File Date: " & f.Name & " - " & Err.Description
Err.Clear
End If

If not blnFound then ' first
blnFound = True
SetServiceState strServiceName, False

Err.Clear

f.Delete(True)

If Err <> 0 Then
MsgBox "Error: Deleting File: " & f.Name & " - " & Err.Description
Err.Clear
End If

If blnFound Then
SetServiceState strServiceName, True
End If

End If

End If 'datediff
Next 'f in odir.files
End If 'odir files count
Else
MsgBox "Error: Directory; " & sdir & " Does Not Exist"
WScript.Quit
End If

'//////////////////////////////////////////////////////////
'/ Functions
'//////////////////////////////////////////////////////////


'----------------------------------------------------------------------------------------------------------------------------------

Function SetServiceState( strServiceName, bState ) ' true = Start ; false = Stop

Dim objWMIService, colListOfServices, objService, strServiceState

On Error Resume Next

Err.Clear

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

If Err <> 0 Then
MsgBox "Error Getting Wmi Service - " & Err.Description
Err.Clear

Else

Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='" & strServiceName & "'")

If Err <> 0 Then
MsgBox "Error Getting Service Collection - " & Err.Description
Err.Clear
Else

For Each objService in colListOfServices

If bState = False Then
objService.StopService()

Do Until strServiceState = "Stopped"
strServiceState = GetServiceState(strServiceName)

''' You may want to put a timeout here in case the service fails to stop to avoid an endless loop.

WScript.Sleep 200
Loop

Else
objService.StartService()

Do Until strServiceState = "Running"
strServiceState = GetServiceState(strServiceName)

''' You may want to put a timeout here in case the service fails to start to avoid an endless loop.

WScript.Sleep 200
blnFound = False
Loop

End If

Next

End If

End If

Set colListOfServices = Nothing
Set objWMIService = Nothing

End Function

'----------------------------------------------------------------------------------------------------------------------------------

Function GetServiceState( strServiceName )

Dim objWMIService, colListOfServices, objService

GetServiceState = ""

On Error Resume Next

Err.Clear

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

If Err <> 0 Then
MsgBox "Error Getting Wmi Service - " & Err.Description
Err.Clear

Else

Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='" & strServiceName & "'")

If Err <> 0 Then
MsgBox "Error Getting Service Collection - " & Err.Description
Err.Clear
Else

For Each objService in colListOfServices

GetServiceState = objService.State

Next
End If

End If

If GetServiceState = "" Then
GetServiceState = "Unknown"
End If

Set colListOfServices = Nothing
Set objWMIService = Nothing

End Function
Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
Great job, thanks for sharing.

Little issue: you've voided the usefulness of the variable "blnFirst", so now the service is stopped and started for each file found. Shouldn't be a real problem though.

But using the Functions and adding error checking is a really good job which will help others looking for a similar solution here.
JCIT2009Director

Author

Commented:
Hi - no probs for sharing - I wouldnt have got this far without your help. I'll hand out some points soon. ;)

Can you see how I could better this to only stop the service once then? Please feel free to advise.. :)
Software Engineer
CERTIFIED EXPERT
Commented:
Well yeah, I would advise to adjust the logic to set blnFound to False at the start, then stop the service when you find the first file to be deleted and set blnFound to True, so far no problem, then not touch it anymore (you set it to false now in the function SetServiceState and call that inside the 'files' loop) and only use it after the For-Next loop to determine the necessity to call "start service". This is all non-essential by the way but if you would want to run this script in a schedule it may be useful to skip stopping and starting the service every time unless it's really necessary.

Applying that logic to your new code (mainly moving some lines around again):

Option Explicit

Dim blnFound, strServiceName, sdir, CurrentDateTime, fso, odir, f, GracePeriodMinuteCount

'//////////////////////////////////////////////////////////
'/ Variables
'//////////////////////////////////////////////////////////

strServiceName = "spooler"
sdir="c:\windows\system32\spool\printers"
CurrentDateTime = Now
GracePeriodMinuteCount = 30

blnFound = False

'//////////////////////////////////////////////////////////
'/ Main Code
'//////////////////////////////////////////////////////////

Set fso=createobject("scripting.filesystemobject")

If fso.folderexists(sdir) then
 Set odir=fso.getfolder(sdir)

 On Error Resume Next
 Err.Clear
 If (odir.Files.Count > 0) Then 
  For each f in odir.Files

   If Err <> 0 Then 
    MsgBox "Error Fetching Files in: " & sdir & " - " & Err.Description
    Err.Clear
   End If

   On Error Resume Next
   If (datediff("n",f.datelastmodified, CurrentDateTime) > GracePeriodMinuteCount) then

    If Err <> 0 Then 
     MsgBox "Error Fetching File Date: " & f.Name & " - " & Err.Description
     Err.Clear
    End If

    If not blnFound then ' first
     blnFound = True
     SetServiceState strServiceName, False
     Err.Clear
    End If

    f.Delete(True)

    If Err <> 0 Then 
     MsgBox "Error: Deleting File: " & f.Name & " - " & Err.Description
     Err.Clear
    End If

   End If 'datediff
  Next 'f in odir.files

  If blnFound Then 
   SetServiceState strServiceName, True
  End If 

 End If 'odir files count 
Else
 MsgBox "Error: Directory; " & sdir & " Does Not Exist"
 WScript.Quit
End If

'//////////////////////////////////////////////////////////
'/ Functions
'//////////////////////////////////////////////////////////


'----------------------------------------------------------------------------------------------------------------------------------

Function SetServiceState( strServiceName, bState ) ' true = Start ; false = Stop
 Dim objWMIService, colListOfServices, objService, strServiceState
 On Error Resume Next 
 Err.Clear
 Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
 If Err <> 0 Then
  MsgBox "Error Getting Wmi Service - " & Err.Description
  Err.Clear
 Else 
  Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  If Err <> 0 Then 
   MsgBox "Error Getting Service Collection - " & Err.Description
   Err.Clear
  Else
   For Each objService in colListOfServices
    If bState = False Then
     objService.StopService()
     Do Until strServiceState = "Stopped"
      strServiceState = GetServiceState(strServiceName)
      ''' You may want to put a timeout here in case the service fails to stop to avoid an endless loop.
      WScript.Sleep 200
     Loop
    Else
     objService.StartService()
     Do Until strServiceState = "Running"
      strServiceState = GetServiceState(strServiceName)
      ''' You may want to put a timeout here in case the service fails to start to avoid an endless loop.
      WScript.Sleep 200
      'blnFound = False
     Loop
    End If
   Next
  End If
 End If 
 Set colListOfServices = Nothing
 Set objWMIService = Nothing
End Function

'----------------------------------------------------------------------------------------------------------------------------------

Function GetServiceState( strServiceName ) 
 Dim objWMIService, colListOfServices, objService
 GetServiceState = ""
 On Error Resume Next 
 Err.Clear
 Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
 If Err <> 0 Then
  MsgBox "Error Getting Wmi Service - " & Err.Description
  Err.Clear
 Else 
  Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='" & strServiceName & "'")
  If Err <> 0 Then 
   MsgBox "Error Getting Service Collection - " & Err.Description
   Err.Clear
  Else
   For Each objService in colListOfServices
    GetServiceState = objService.State
   Next
  End If
 End If 
 If GetServiceState = "" Then 
  GetServiceState = "Unknown"
 End If
 Set colListOfServices = Nothing
 Set objWMIService = Nothing
End Function 

Open in new window

JCIT2009Director

Author

Commented:
cool - thanks - will try that today.
JCIT2009Director

Author

Commented:
all seems to work now. Thanks for everyones help! x

Commented:
I have a question regarding this topic

I have a lot of print server and spool folder is not always at the same place

is there a way through vbs to find spool folder
Robert SchuttSoftware Engineer
CERTIFIED EXPERT

Commented:
You should not post comments like this on old questions since the experts will only be alerted about new questions and also they should be able to earn points. That being said, it might be a valuable addition to this particular code, Unfortunately, I'm not able to spend much time on this now so will just give some general info:

1) the spool folder can be found in the registry under: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers

2) code to read the registry in vbscript can be found here for example: http://blogs.msdn.com/b/alejacma/archive/2008/04/11/how-to-read-a-registry-key-and-its-values.aspx