1 (изменено: J.Rico, 2008-05-28 12:26:36)

Тема: VBS\JS: лог печати - как сделать?

Народ, подскажите мне вот что: мне нужно получать инфу о том кто, когда (время, дата) и сколько печатает на принтере - т.е. чтобы я со своего компа мог эту инфу посмотреть. Я поискал проги для винды бесплатные, но бесплатных нет (за деньги лучший вариант PrintControl 3.xx).
Вот возникла мысля - можно как-то сделать такой скрипт, который подгружается при входе в систему и когда юзер что-то отсылает на печать (принтер может быть как напрямую подключенный к компу юзера так и сетевой), то в лог пишется имя принтера на котором печатали, имя юзера, время когда отправили на печать и кол-во страниц документа (?!), а сам лог хранился бы на расшаренном сетевом ресурсе в папке имя которой соответствует имени компа с которого печатали?
На каждую дату свой отдельный лог-файл. Т.е. чтобы можно было посмотреть кто и сколько страниц отпечатал на определенном принтере.

Вот как-то так...

Я таких сложных скриптов не писал и поэтому даж не знаю возможно ли такой скрипт сделать или тут уже программа нужна?

2

Re: VBS\JS: лог печати - как сделать?

Может, чем-то поможет:
VBS:VBScript + logparser.exe (2.2) + *.tpl

Предложения в русском языке начинаются с большой буквы и заканчиваются точкой.
В названии ветки всегда должен быть указан язык программирования или среда исполнения скрипта, если это возможно.

3

Re: VBS\JS: лог печати - как сделать?

J.Rico пишет:

Народ, подскажите мне вот что: мне нужно получать инфу о том кто, когда (время, дата) и сколько печатает на принтере - т.е. чтобы я со своего компа мог эту инфу посмотреть...

Решал я когда-то подобную задачу, только для более простого случая, а именно:
- к некоей сетевой станции подключен принтер общего доступа;
- пользователь, запускающий сценарий, имеет права администратора на этой станции;
- для сбора указанных сведений анализируется журнал системных событий этой станции;
- период очистки журнала совпадает с периодом сбора сведений, причём очистка выполняется только после выполнения рассматриваемой задачи.
Кроме того, меня интересовал только суммарный объём напечатанного, а не раскладка заданий печати по датам.
Однако, полагаю, что приспособить этот пример к решению Вашей задачи несложно.
С моей точки зрения, такой способ гораздо надёжнее, чем интерактивный, т.к. зависит лишь от периодичности очистки журнала событий. Нужную же периодичность совсем несложно настроить с помощью групповой политики безопасности.
По сути этот метод аналогичен тому, на который уже дал ссылку The gray Cardinal. Разница лишь в том, что здесь не требуются какие-либо утилиты.

Dim objWMI, objCollection, objItem, lngNumEvents
Dim strMsg, intPosL, intPosR, strOwner, intPages
Dim dtmEventDate, dtmFirstDate, dtmLastDate
Dim objDict, objFS, objFile
Const strComputer = "здесь - DNS-имя станции, журнал которой анализируется"
Const strResFile = "C:\Temp\Results.txt"
dtmFirstDate = DateValue("01.05.2008")
dtmLastDate = DateValue("28.05.2008")
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objCollection = objWMI.ExecQuery("SELECT * FROM Win32_NTLogEvent WHERE Logfile='System' " & _
    "AND EventType=3 AND SourceName='Print' AND EventCode=10")
lngNumEvents = objCollection.Count
If lngNumEvents > 0 Then
    Wscript.Echo "Найдено событий указанного вида: " & lngNumEvents
    Set objDict = CreateObject("Scripting.Dictionary")
    objDict.CompareMode = 1
    For Each objItem In objCollection
        dtmEventDate = Date_Convert(CStr(objItem.TimeWritten))
        If dtmFirstDate <= dtmEventDate And dtmEventDate <= dtmLastDate Then
            strMsg = objItem.Message
            intPosL = InStr(1, strMsg, "владельца", vbTextCompare)
            intPosR = InStr(1, strMsg, "напечатан", vbTextCompare)
            strOwner = Mid(strMsg, intPosL + 10, intPosR - intPosL - 11)
            intPosL = InStrRev(strMsg, ":")
            intPages = CInt(Mid(strMsg, intPosL + 2))
            If objDict.Exists(strOwner) Then
                objDict.Item(strOwner) = objDict.Item(strOwner) + intPages
            Else
                objDict.Add strOwner, intPages
            End If
        End If
    Next
    Set objFS = CreateObject("Scripting.FileSystemObject")
    Set objFile = objFS.CreateTextFile(strResFile, True)
    For Each objItem In objDict.Keys
        objFile.WriteLine (objItem & " = " & objDict.Item(objItem))
    Next
    objFile.Close
    Set objFile = Nothing
    objDict.RemoveAll
    Set objDict = Nothing
    Wscript.Echo "Готово."
Else
    Wscript.Echo "Событий указанного вида в журнале не обнаружено."
End If
Set objCollection = Nothing
Set objWMI = Nothing

Function Date_Convert(strDTM)
Date_Convert = DateValue(Mid(strDTM, 7, 2) & "." & Mid(strDTM, 5, 2) & "." & Mid(strDTM, 1, 4))
End Function

4

Re: VBS\JS: лог печати - как сделать?

Dmitrii, я ваш скрипт как есть скопировал, изменил strComputer = "Komp", но скрипт "говорит", что событий данного типа не обнаружено. Каким образом вы получили файл C:\Temp\results.txt - сохраняли журнал или как? у меня такого файла нет.

и еще вопрос (наверное даже ко всем, а не только к Dmitrii): например такая ситуация (из практики): послали из 1С печатать документ (накладную или чо там еще есть), но принтер ничего не печатает, на неск секунд появляется значок принтера в трее и исчезает, т.е. задание в очередь то попадает. Пользователь посылает док на печать еще раз - печатает. Собственно сам вопрос: при неудачной попытке печати событие все равно ведь в журнал попадает и таким образом в отчете считатаются страницы, которые на самом деле не печатались

5

Re: VBS\JS: лог печати - как сделать?

А нельзя сделать лог печати одного компьютера. Т.е. чтобы статистика сохранялась только с данного компьютера (Быть даже не подключенного к сети), а сам лог сохранялся в файл...

Счастья. Для всех. Даром. И пусть никто не уйдет обиженным... (с) Стругацкие "Пикник на обочине"

6

Re: VBS\JS: лог печати - как сделать?

J.Rico пишет:

... скрипт как есть скопировал, изменил strComputer = "Komp", но скрипт "говорит", что событий данного типа не обнаружено...

Проверьте визуально, есть ли в журнале "Система" нужного компьютера (в Вашем случае - "Komp") записи типа Уведомление (фрагмент кода: EventType=3), источник которых именуется Print (фрагмент кода: SourceName='Print'), и код события у которых равен 10 (фрагмент кода: EventCode=10).

J.Rico пишет:

Каким образом вы получили файл C:\Temp\results.txt - сохраняли журнал или как? у меня такого файла нет.

Файл формируется самим сценарием по результатом фильтрации журнала событий. Разумеется, в Вашем случае файла результатов нет, т.к. ни одной подходящей записи не найдено.

J.Rico пишет:

... Собственно сам вопрос: при неудачной попытке печати событие все равно ведь в журнал попадает и таким образом в отчете считатаются страницы, которые на самом деле не печатались

А что, при такой фиктивной печати в журнале событий появляется запись об успешной обработке задания на печать?

7

Re: VBS\JS: лог печати - как сделать?

Archangel пишет:

А нельзя сделать лог печати одного компьютера. Т.е. чтобы статистика сохранялась только с данного компьютера (Быть даже не подключенного к сети), а сам лог сохранялся в файл...

Если речь о предложенном мной примере сценария, то он как раз и предназначен для обработки журнала одного компьютера. Выборка из этого журнала, касающаяся печати, сохраняется в файл, правда, уже после некоторой статистической обработки. Но можно, разумеется, и без обработки.
Или я Вас не понял?

8

Re: VBS\JS: лог печати - как сделать?

Да нет. Все видимо правильно. ... Просто еще не было времени разобраться с твоим примером. Мне нужен скрипт для одного компьютера.  Без указания сетевого имени и т.д. ...

Счастья. Для всех. Даром. И пусть никто не уйдет обиженным... (с) Стругацкие "Пикник на обочине"

9 (изменено: alexii, 2008-06-05 17:11:47)

Re: VBS\JS: лог печати - как сделать?

Проверьте визуально, есть ли в журнале "Система" нужного компьютера (в Вашем случае - "Komp") записи типа Уведомление (фрагмент кода: EventType=3), источник которых именуется Print (фрагмент кода: SourceName='Print'), и код события у которых равен 10 (фрагмент кода: EventCode=10).

У меня такое наблюдается только на серверах печати (и на сервере терминалов). При локальной печати — в журнале тишина. Может быть, надо что-то настроить, чего я не знаю?!

P.S. Сообщения об ошибках печати появляются.

10

Re: VBS\JS: лог печати - как сделать?

Dmitrii, в журнале отсортировал по Источник=Print -> сообщения только об ошибках есть

11

Re: VBS\JS: лог печати - как сделать?

alexii пишет:

У меня такое наблюдается только на серверах печати (и на сервере терминалов). При локальной печати — в журнале тишина...

J.Rico пишет:

в журнале отсортировал по Источник=Print -> сообщения только об ошибках есть

Приношу свои извинения за плохо протестированный сценарий. Дело в том, что я писал его и, соответственно, проверял на работоспособность именно для сервера печати, работающего под управлением Windows 2003. А так как в работе сценарий не пригодился, то я отправил его "в запас" и забыл о подробностях тестирования.
Очевидно, что на рядовых станциях он сможет работать лишь в том случае, если на них можно будет включить регистрацию события об успешном завершении задания на печать в системном журнале.

12

Re: VBS\JS: лог печати - как сделать?

можно будет включить регистрацию события об успешном завершении задания на печать в системном журнале

Можете расписать требуемые действия подробно, по шагам?

13

Re: VBS\JS: лог печати - как сделать?

alexii пишет:

Можете расписать требуемые действия подробно, по шагам?

К сожалению, пока не могу, т.к. это лишь предположение.
Думаю, имеет смысл порыться в справочниках по реестру на предмет поиска нужного раздела (ключа).

14

Re: VBS\JS: лог печати - как сделать?

Опробовал в домене 2003.
2 проблемы:

1. если диапазон дат мониторинга больше реально наступившего, т.е. если сейчас я выберу параметр   dtmLastDate = DateValue("20.11.2010"),
то сначала будет сообщение о кол-ве найденных сообщений (не ноль), а затем:
Строка: 23
Символ: 13
Ошибка: Недопустимый вызов или аргумент процедуры: 'Mid'
Код: 800A0005

2. в остальных случаях кол-во событий есть, а файл Results.txt пустой.

15

Re: VBS\JS: лог печати - как сделать?

Позвольте и мне выложить своё решение (у меня оно для принтеров OKI "окушек")
Мониторинг производиться только когда в драйвере принтера указано "сохранять задания после печати" - это однозначно !!! Не наступайте больше на эти грабли !!!
Устанавливать скрипт на компах, куда принтер подключен физически !
Потом просматривать логи на сетевой шаре в соответсвующем названию компа логе...

А вот и код...

Set objNetwork = CreateObject("Wscript.Network")
CompName = objNetwork.ComputerName
          
strComputer = "."
Set objFSO = CreateObject("Scripting.FileSystemObject")
Const ForAppending = 8

' даём принтеру установку, чтобы он сохранял задания для логирования скриптом
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colInstalledPrinters = objWMIService.ExecQuery("Select * from Win32_Printer")
For Each objPrinter in colInstalledPrinters
If Left(objPrinter.DeviceID,3)="OKI" then
PrinterID=objPrinter.DeviceID
objPrinter.KeepPrintedJobs = True
objPrinter.Put_
End if
Next

'отменяем все задания
Set colInstalledPrinters = objWMIService.ExecQuery("Select * from Win32_Printer")
For Each objPrinter in colInstalledPrinters
objPrinter.CancelAllJobs()
Next

'удаляем все задания
Set colPrintJobs = objWMIService.ExecQuery("Select * from Win32_PrintJob")
For Each objPrintJob in colPrintJobs 
objPrintJob.Delete_
Next

' ну и мониторим каждые 60 сек события о печати :-)
Set colPrintJobs = objWMIService.ExecNotificationQuery("select * from __InstanceCreationEvent Within 60 where TargetInstance isa 'Win32_PrintJob' and TargetInstance.JobStatus='Напечатано'")
Do While True
    Set objPrintJob = colPrintJobs.NextEvent
    If InStr(objPrintJob.TargetInstance.Name, PrinterID)<>0 Then 
        docname=objPrintJob.TargetInstance.Document
        size=objPrintJob.TargetInstance.Size
        owner=objPrintJob.TargetInstance.Owner
        jobstamp=WMIDateToString(objPrintJob.TargetInstance.TimeSubmitted)
        pages=objPrintJob.TargetInstance.TotalPages
        On error resume next
        Set LogFile = objFSO.OpenTextFile("\\192.168.42.90\Pubs\PM\" & CompName & "_Print.Log", ForAppending, True)
        LogFile.WriteLine Owner & "   " & jobstamp & "   " & docname & "   " & size & "   " & pages
        LogFile.Close
        On error goto 0
    End If
Loop 


Function WMIDateToString(dtmDate)

WMIDateToString = CDate(Mid(dtmDate, 5, 2) & "/" & _
                  Mid(dtmDate, 7, 2) & "/" & _
                  Left(dtmDate, 4) & "   " & _
                  Mid(dtmDate, 9, 2) & ":" & _
                  Mid(dtmDate, 11, 2) & ":" & _
                  Mid(dtmDate, 13, 2))

End Function
Времени не хватает... :-(

16 (изменено: Dmitrii, 2010-11-18 16:37:34)

Re: VBS\JS: лог печати - как сделать?

bnp322 пишет:

... если диапазон дат мониторинга больше реально наступившего, т.е. если сейчас я выберу параметр   dtmLastDate = DateValue("20.11.2010"),
то сначала будет сообщение о кол-ве найденных сообщений (не ноль), а затем:
Строка: 23
Символ: 13
Ошибка: Недопустимый вызов или аргумент процедуры: 'Mid'
Код: 800A0005

Вообще-то, диапазон дат (если их значения заданы корректно) не должен вызывать никакой ошибки. Можно, например, задать дату начала диапазона более позднюю, чем дата окончания диапазона. Сценарий должен отработать без ошибок (проверялось), но файл отчёта, разумеется будет пустым. Но раз у Вас возникает ошибка, то следует заняться отладкой:
- "отловите" ту итерацию цикла, при работе которой возникает ошибка;
- проконтролируйте значения переменных intPosL и intPosR;
- соотнесите полученные значения с содержимым переменной strMsg.

Если не справитесь самостоятельно, то выложите сюда текст, являющийся значением переменной strMsg.

Кстати, имя пользователя, создавшего задание печати, можно получить и проще (найденный Вами сценарий уже староват): objItem.User

bnp322 пишет:

... в остальных случаях кол-во событий есть, а файл Results.txt пустой.

Такая ситуация характерна для случая, когда в журнале нет сообщений, дата создания которых попадает в заданный диапазон, либо границы диапазона (как уже упоминалось выше) заданы неверно.


Евген пишет:

... Мониторинг производиться только когда в драйвере принтера указано "сохранять задания после печати" - это однозначно !!!

Эта фраза относится к сценарию из Вашего сообщения, или из сообщения #3?
Если - последнее, то Вы ошибаетесь. Драйвер принтера здесь совершенно "невиновен". Протоколирование успешных событий печати - системная настройка. На серверных платформах "окошек" она включена по умолчанию. На XP включается так:
Папка "Принтеры и факсы" - меню "Файл" - пункт "Свойства сервера" - вкладка "Дополнительные параметры" - "коробочка" "Вести журнал сообщений очереди печати".
На Vista и 7 - не проверял.

17 (изменено: bnp322, 2010-11-18 16:59:24)

Re: VBS\JS: лог печати - как сделать?

Поверил!
Если в ХР включить ведение лога - все хорошо - даже если даты за пределами.  Переменные intPosL и intPosR были равны 42 и 56 в конце цикла.
Независимо от 1 или двух напечатанных страниц. Файл Results.txt адекватен.
Если я пытаюсь все это сделать на 2003 терминальном сервере, где печатают ежедневно, то :
Количество событий = 276 неизменно. Т.е. если я выберу анализ  1 дня или 1 месяца ничего не изменится!
Я пытался получить переменные, выглядело это так

 ...
ll = intPosL
rr = intPosR
            strOwner = Mid(strMsg, intPosL + 10, intPosR - intPosL - 11)
 ...           
Wscript.Echo ll
Wscript.Echo rr
    Wscript.Echo "Готово."

"Вылазили" пустые окна без всяких символов

18

Re: VBS\JS: лог печати - как сделать?

Dmitrii пишет:
Евген пишет:

... Мониторинг производиться только когда в драйвере принтера указано "сохранять задания после печати" - это однозначно !!!

Эта фраза относится к сценарию из Вашего сообщения, или из сообщения #3?

Из моего - однозначно !

Времени не хватает... :-(

19

Re: VBS\JS: лог печати - как сделать?

bnp322 пишет:

... Если я пытаюсь все это сделать на 2003 терминальном сервере, где печатают ежедневно, то : Количество событий = 276 неизменно. Т.е. если я выберу анализ  1 дня или 1 месяца ничего не изменится <...> "Вылазили" пустые окна без всяких символов

1. Количество найденных событий никак не зависит от диапазона дат, который назначен сценарию для анализа.
2. Проверьте настройки периодичности очистки журнала событий.
3. Имя пользователя, как уже сказано в моём предыдущем сообщении, определяйте так: objItem.User.
4. Приведите содержимое одной записи журнала событий о результатах обработки задания печати. Конфиденциальные данные можете заменить на вымышленные.

20

Re: VBS\JS: лог печати - как сделать?

Это?

Event Type: Information
Event Source: Print
Event Category: None
Event ID: 10
Date: 18.11.2010
Time: 16:42:46
User: xyz\popova
Computer: TERMINAL
Description:
Document 18, Табличный документ owned by popova was printed on hp LaserJet 1320 PCL 6 (from REK1) in session 8 via port TS010.  Size in bytes: 577450; pages printed: 2

21

Re: VBS\JS: лог печати - как сделать?

bnp322 пишет:

Это?

Да.

bnp322 пишет:

owned by popova <...> pages printed: 2

Вы обратили внимание на то, что у Вас текст сообщения на английском (по крайней мере, в нужной для обработки части), а сценарий ищет слова-флаги на русском? Если нет, то вот и причина некорректной работы.

22

Re: VBS\JS: лог печати - как сделать?

Event Source: Print
Event Category: None
Event ID: 10
Date: 18.11.2010
Time: 21:33:33
User: xyz\user
Computer: TERMINAL
Description:
Document 21, Document owned by bnp was printed on hp LaserJet 1320 PCL 6 via port reklama.  Size in bytes: 1008; pages printed: 1

23

Re: VBS\JS: лог печати - как сделать?

Он ищет слова "владельца" и "напечатан"  ?

24 (изменено: Dmitrii, 2010-11-18 17:45:43)

Re: VBS\JS: лог печати - как сделать?

bnp322, достаточно текста одного сообщения. Вероятную причину ошибки я уже указал.

25 (изменено: bnp322, 2010-11-18 17:59:09)

Re: VBS\JS: лог печати - как сделать?

Хорошо!

Рабочий кусочек кода для ENG Windows:

            intPosL = InStr(1, strMsg, "owned", vbTextCompare)
            intPosR = InStr(1, strMsg, "printed", vbTextCompare)
            strOwner = Mid(strMsg, intPosL + 9, intPosR - intPosL - 14)

Спасибо!:)