Скрипт позволяет собирать события печати из журналов Windows с локального или удаленного компьютера(ов) и импортировать их в базу Oracle.
Требования для машины, на которой запускаете скрипт:
- ОС Windows (7, XP, Server 2003, Server 2008)
- Oracle client (or instant client) version 10.2 and above.
- Запускать скрипт под пользователем, который входит в группу Администрирования на других компьютерах сети.
Требования к базе Oracle:
- Oracle DB 10.2 and above.
- Создать в какой-нибудь схеме базы Oracle таблицы:
/* список компьютеров, по которым нужно собирать события печати */ CREATE TABLE PRINTLOG_COMPUTERS (COMPUTER VARCHAR2(100)); /* сюда будут писаться данные по печати */ CREATE TABLE PRINTLOG (SYSDATETIME DATE, CREATEDTIME DATE, OS VARCHAR2(50), EVENTID NUMBER, SOURCENAME VARCHAR2(128), COMPUTER VARCHAR2(100), USERNAME VARCHAR2(128), MESSAGE VARCHAR2(4000)); /* сюда будут писаться ошибки, возникающие при сборе событий */ CREATE TABLE PRINTLOG_ERROR (SYSDATETIME DATE, COMPUTER VARCHAR2(100), ERRORMESSAGE VARCHAR2(512));
- В таблицу PRINTLOG_COMPUTERS внести имена компьютеров, по которым будет собираться статистика печати.
Требования к компьютерам, с которых будут собираться события печати из журналов Windows:
- Желательно, чтобы компьютеры были под управлением Windows (7, XP, Server 2003, Server 2008)
- И чтобы находились в одном домене
Исходник скрипта, с комментариями:
'### [ VBScript ] '### (c) 02.04.2015 '### What: collects events printing (10, 307) from Windows events logs on local or remote computer and writes them to the Oracle database '### Author: souluran Dim objWMIService Dim colLoggedEvents Dim colLogFiles Dim ObjLogFile Dim objEvent Dim errCon Dim errMessage Dim strSearchString Dim con Dim objRecordset Dim PROC, SQL, ERRINS, INS Dim objRegistry Dim strKeyPath Dim flag Dim arrSubKeys Dim subkey Dim EventCode Dim LogFile Dim OverWrite Const HKEY_LOCAL_MACHINE = &H80000002 On Error Resume Next '--> connection parameters to Oracle Driver = "************" '--> for example "Oracle in instantclient_11_2" dbName = "************" dbUser = "************" '--> better to have a user with the DBA or have privileges Select/Insert/Delete on tables PRINTLOG_COMPUTERS, PRINTLOG, PRINTLOG_ERROR Password = "************" dbSchema = "************" '--> scheme that created the table PRINTLOG_COMPUTERS, PRINTLOG, PRINTLOG_ERROR '--> open connect to Oracle Set con = CreateObject("ADODB.Connection") con.ConnectionTimeOut = 20 con.CommandTimeout = 120 con.Open "Driver={" & Driver & "};DBQ=" & dbName & ";UID=" & dbUser & ";PWD=" & Password Err.Clear '--> check connect to Oracle If Err.Number <> 0 Then 'error handling: errCon = "ORACLE: " & Err.Number & " Srce: " & Err.Source & " Desc: " & Err.Description 'WScript.Echo errStr Err.Clear 'WScript.Quit End If '--> set the start and the end dates for the collection begdate = "20150101 00:00:00" enddate = "20150430 23:59:59" '--> get list of computers SQL = "select COMPUTER from " & dbSchema & ".PRINTLOG_COMPUTERS order by 1" Set objRecordset = con.Execute(SQL) Do Until objRecordset.EOF Computer = objRecordset.Fields("COMPUTER").Value 'WScript.Echo Computer Err.Clear '--> check computer to access Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & Computer & "\root\cimv2") If Err.Number <> 0 Then errMessage = Err.Description 'WScript.Echo errMessage ERRINS = "INSERT INTO " & dbSchema & ".printlog_error VALUES(sysdate,'" & Computer & "','" & errMessage & "')" Set objRecordsetErr = con.Execute(ERRINS) Err.Clear errMessage = vbNullString Else '--> check version OS Windows Set colOperatingSystems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem") OS = vbNullString For Each objOperatingSystem in colOperatingSystems OS = objOperatingSystem.Caption Exit For Next 'WScript.Echo OS '--> set logfile and evencode for Windows XP and 7 If InStr(OS, "Windows XP") > 0 Or InStr(OS, "Windows(R) XP") > 0 Or InStr(OS, "Server 2003") > 0 Then LogFile = "System" EventCode = "10" 'event print for Windows XP (2003) ElseIf InStr(OS, "Windows 7") > 0 Or InStr(OS, "Windows(R) 7") Or InStr(OS, "Server 2008") > 0 Then LogFile = "Microsoft-Windows-PrintService/Operational" EventCode = "307" 'event print for Windows 7 (2008) '--> check exists registry key for read printing events on Windows 7 Set objRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & Computer & "\root\default:StdRegProv") strKeyPath = "SYSTEM\CurrentControlSet\services\eventlog" objRegistry.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubKeys flag = 0 For Each subkey In arrSubKeys If subkey = LogFile Then flag = 1 Exit For End If Next If flag = 0 Then 'WScript.Echo "Create new key Microsoft-Windows-PrintService/Operational." strKeyPath = "SYSTEM\CurrentControlSet\services\eventlog\Microsoft-Windows-PrintService/Operational" objRegistry.CreateKey HKEY_LOCAL_MACHINE, strKeyPath End If End If Rec = 0 '--> check the log for events Set colLogFiles = objWMIService.ExecQuery("Select * from Win32_NTLogEvent Where Logfile = '" & LogFile & "' and EventCode = '" & EventCode & "'") For Each ObjLogFile In colLogFiles Rec = 1 Exit For Next If Rec = 0 Then errMessage = "The " & LogFile & " are failed or not contained events " & EventCode 'WScript.Echo errMessage ERRINS = "INSERT INTO " & dbSchema & ".PRINTLOG_ERROR VALUES(sysdate,'" & Computer & "','" & errMessage & "')" Set objRecordsetErr = con.Execute(ERRINS) errMessage = vbNullString Else '--> option overwrite exists records in table (0 - OFF, 1 - ON) OverWrite = 0 If OverWrite = 1 Then DEL = "DELETE FROM " & dbSchema & ".PRINTLOG where computer = '" & computer & "' and trunc(CREATEDTIME) >= to_date(substr('" & begdate & "', 1, 8), 'yyyymmdd') " _ & " and trunc(CREATEDTIME) <= to_date(substr('" & enddate & "', 1, 8), 'yyyymmdd')" Set objRecordsetDel = con.Execute(DEL) End If '--> search events in a given period cnt = 0 Set colLoggedEvents = objWMIService.ExecQuery("Select * from Win32_NTLogEvent Where Logfile = '" & LogFile & "' and EventCode = '" & EventCode & "' and TimeGenerated >= '"& begdate &"' and TimeGenerated <= '" & enddate & "'") cnt = colLoggedEvents.Count If cnt > 0 Then 'WScript.Echo cnt For Each objEvent In colLoggedEvents strSearchString = objEvent.Message EventCode = objEvent.EventCode SourceName = objEvent.SourceName If InStr(objEvent.ComputerName, ".keramin.int") > 0 Then ComputerName = LCase(objEvent.ComputerName) Else ComputerName = LCase(objEvent.ComputerName) & ".keramin.int" End If UserName = LCase(objEvent.User) CreatedTime = objEvent.TimeWritten Message = Replace(objEvent.Message, "'", "") INS = "INSERT INTO " & dbSchema & ".PRINTLOG VALUES(sysdate, to_date(substr('" & CreatedTime & "', 1, 14), 'yyyymmddhh24miss'),'" & OS & "','" & EventCode & "','" & SourceName & "','" & ComputerName & "','" & UserName & "','" & Message & "')" Set objRecordsetIns = con.Execute(INS) Next Else errMessage = "There was no events print in " & LogFile & " from " & begdate & " to " & enddate 'WScript.Echo errMessage 'ERRINS = "INSERT INTO " & dbSchema & ".PRINTLOG_ERROR VALUES(sysdate,to_date(substr('" & begdate & "', 1, 8), 'yyyymmdd'),'" & Computer & "','" & errMessage & "')" 'Set objRecordsetErr = con.Execute(ERRINS) errMessage = vbNullString End If End if End If objRecordset.MoveNext Loop '--> close connect to Oracle con.Close Set objRecordsetErr = Nothing Set objRecordsetIns = Nothing Set objRecordsetDel = Nothing Set con = Nothing > End if End If objRecordset.MoveNext Loop '--> close connect to Oracle con.Close Set objRecordsetErr = Nothing
А вот маленький запрос =), который возвращает нужные для статистики данные по таблице PRINTLOG:
SELECT SYSDATETIME, CREATEDTIME, EVENTID, SOURCENAME, COMPUTER, OS, USERNAME, SUBSTR ( REGEXP_REPLACE (MESSAGE, 'Документ \d+, |Document \d+, ', ''), 1, REGEXP_INSTR ( REGEXP_REPLACE (MESSAGE, 'Документ \d+, |Document \d+, ', ''), 'владельца|owned|, которым владеет') - 1) DOC, REGEXP_REPLACE ( TRIM ( REGEXP_REPLACE ( SUBSTR ( MESSAGE, REGEXP_INSTR ( MESSAGE, 'владельца|owned by|, которым владеет')), 'владельца |owned by |, которым владеет')), ' (.*)') OWNER, SUBSTR ( REGEXP_REPLACE ( SUBSTR ( MESSAGE, REGEXP_INSTR ( MESSAGE, 'напечатан на |был распечатан на |was printed ')), 'напечатан на |был распечатан на |was printed on '), 1, REGEXP_INSTR ( REGEXP_REPLACE ( SUBSTR ( MESSAGE, REGEXP_INSTR ( MESSAGE, 'напечатан на |был распечатан на |was printed on ')), 'напечатан на |был распечатан на |was printed on '), 'через порт|via port|through port') - 2) PRINTER, SUBSTR ( REGEXP_REPLACE ( SUBSTR ( MESSAGE, REGEXP_INSTR (MESSAGE, 'через порт |via port |through port ')), 'через порт |via port |through port '), 1, REGEXP_INSTR ( REGEXP_REPLACE ( SUBSTR ( MESSAGE, REGEXP_INSTR ( MESSAGE, 'через порт |via port |through port ')), 'через порт |via port |through port '), ' Размер: | Размер в байтах: | Size in bytes: ') - 3) PORT, SUBSTR ( REGEXP_REPLACE ( SUBSTR ( MESSAGE, REGEXP_INSTR ( MESSAGE, 'Размер: |Размер в байтах: |Size in bytes: ')), 'Размер: |Размер в байтах: |Size in bytes: '), 1, REGEXP_INSTR ( REGEXP_REPLACE ( SUBSTR ( MESSAGE, REGEXP_INSTR ( MESSAGE, 'Размер: | Размер в байтах: | Size in bytes: ')), 'Размер: | Размер в байтах: | Size in bytes: '), ' байт;|число страниц: |(.|;) Pages printed: |(.|;) Страниц напечатано: ') - 1) BYTES, TRIM ( REGEXP_REPLACE ( SUBSTR ( MESSAGE, REGEXP_INSTR ( MESSAGE, ' байт; |число страниц: | Pages printed: | Страниц напечатано: ')), ' байт; |число страниц: |Страниц напечатано: |(p|P)ages printed: |[.] Действий пользователя не требуется[.]|[.] No user action is required[.]|' || CHR (13) || CHR (10))) PAGES, MESSAGE FROM printlog ORDER BY 1;
Если будут какие-то вопросы обращайтесь, возможно помогу.
Также в скором времени создам пост с подобный скриптом, но написанном на Python.
Привет вопрос по скрипту. А точно на VBS в Win32_NTLogEvent читает события для печати? Не находит таких событий
Привет.
Все работает и VBS читает Win32_NTLogEvent, если конечно вы включили сбор событий печати (читайте здесь).
А вообще я написал новый сборщик событий печати на python (он работает в разы быстрее этого, т.к. может работать с потоками, может работать как служба Windows, имеет встроенный парсер событий и многое другое), но здесь я его не выложил, т.к. сейчас этот код принадлежит одной компании.