530 lines
18 KiB
Rexx
Executable File
530 lines
18 KiB
Rexx
Executable File
/*----------------------------------------------------------------------------*/
|
|
/* */
|
|
/* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
|
|
/* Copyright (c) 2005-2014 Rexx Language Association. All rights reserved. */
|
|
/* */
|
|
/* This program and the accompanying materials are made available under */
|
|
/* the terms of the Common Public License v1.0 which accompanies this */
|
|
/* distribution. A copy is also available at the following address: */
|
|
/* https://www.oorexx.org/license.html */
|
|
/* */
|
|
/* Redistribution and use in source and binary forms, with or */
|
|
/* without modification, are permitted provided that the following */
|
|
/* conditions are met: */
|
|
/* */
|
|
/* Redistributions of source code must retain the above copyright */
|
|
/* notice, this list of conditions and the following disclaimer. */
|
|
/* Redistributions in binary form must reproduce the above copyright */
|
|
/* notice, this list of conditions and the following disclaimer in */
|
|
/* the documentation and/or other materials provided with the distribution. */
|
|
/* */
|
|
/* Neither the name of Rexx Language Association nor the names */
|
|
/* of its contributors may be used to endorse or promote products */
|
|
/* derived from this software without specific prior written permission. */
|
|
/* */
|
|
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
|
|
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
|
|
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
|
|
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
|
|
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
|
|
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
|
|
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
|
|
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
|
|
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
|
|
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
|
|
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
|
/* */
|
|
/*----------------------------------------------------------------------------*/
|
|
/****************************************************************************/
|
|
/* Name: eventlog.rex */
|
|
/* Type: Open Object Rexx Script */
|
|
/* */
|
|
/* Description: Example of how to use the WindowsEventLog class */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
/* main program */
|
|
|
|
log = .WindowsEventLog~new
|
|
|
|
/******************************************************************************/
|
|
say "=============================================================================="
|
|
say " Display some basic attibutes of a WindowsEventLog object. Consult the"
|
|
say " documentation for an explanation of the meaning of these attributes."
|
|
say
|
|
/******************************************************************************/
|
|
say " Events attribute: " log~events
|
|
say " Current minimum read buffer size:" log~minimumReadBuffer "bytes"
|
|
say " Current minimum read buffer size:" log~minimumRead "KBs"
|
|
say " Minimum read buffer range: " log~minimumReadMin "KBs to" log~minimumReadMax "KBs"
|
|
say
|
|
|
|
/******************************************************************************/
|
|
say "=============================================================================="
|
|
say " Open each event log on this computer and display information about the"
|
|
say " log. Then close the log."
|
|
say
|
|
/******************************************************************************/
|
|
logNames = .array~new
|
|
ret = log~getLogNames(logNames)
|
|
|
|
if ret == 0 then do name over logNames
|
|
ret = log~open( , name)
|
|
|
|
if ret == 0 then do
|
|
say " Event log: " name
|
|
say " Total records: " log~getNumber
|
|
say " First record number" log~getFirst
|
|
say " Last record number " log~getLast
|
|
say " Log is full? " logicalToText(log~isFull)
|
|
log~close
|
|
end
|
|
else do
|
|
say " Error opening the" name "event log rc:" ret
|
|
end
|
|
say
|
|
end
|
|
|
|
|
|
/******************************************************************************/
|
|
say "=============================================================================="
|
|
say "Going to read the 3 oldest records in the Application event Log,"
|
|
say "oldest first. The log is not opened before reading. The open and"
|
|
say "close are done implicitly."
|
|
/******************************************************************************/
|
|
ok = doPause(.false)
|
|
|
|
count = 0
|
|
|
|
if log~getNumber < 3 then do
|
|
say "To few records ("log~getNumber") for this demonstration."
|
|
end
|
|
else do
|
|
-- If the user has set the overwrite option for the event log, the first
|
|
-- record is not always 1. FORWARDS is the default.
|
|
firstRec = log~getFirst
|
|
ret = log~readRecords( , , , firstRec, 3)
|
|
|
|
if ret == 0 then do
|
|
count = displayRecords(log~events)
|
|
end
|
|
else do
|
|
say "Error reading the Application event log rc:" ret
|
|
end
|
|
end
|
|
|
|
say "=========================================================================="
|
|
say count "records read"
|
|
say
|
|
|
|
/******************************************************************************/
|
|
say "=========================================================================="
|
|
say "Going to read the 3 most recent records in the System event Log, the"
|
|
say "most recent first. The log is not opened before reading. The open"
|
|
say "and close are done implicitly."
|
|
/******************************************************************************/
|
|
ok = doPause(.false)
|
|
|
|
count = 0
|
|
|
|
if log~getNumber("", "System") < 3 then do
|
|
say "To few records (" || log~getNumber("", "System") || ") for this demonstration."
|
|
end
|
|
else do
|
|
-- If the user has set the overwrite option for the event log, the most recent
|
|
-- record is not always the same as the record number.
|
|
lastRec = log~getLast( , "System")
|
|
ret = log~readRecords("BACKWARDS", , "System", lastRec, 3)
|
|
|
|
if ret == 0 then do
|
|
count = displayRecords(log~events)
|
|
end
|
|
else do
|
|
say "Error reading the System event log rc:" ret
|
|
end
|
|
end
|
|
|
|
say "=========================================================================="
|
|
say count "records read"
|
|
say
|
|
|
|
/******************************************************************************/
|
|
say "=========================================================================="
|
|
say "Going to read the 3 oldest records in the System event Log, in reverse"
|
|
say "chronological older. The log is opened before any operation, then"
|
|
say "closed when all operations are done. This allows specifying the log"
|
|
say "name only once."
|
|
/******************************************************************************/
|
|
ok = doPause(.false)
|
|
|
|
count = 0
|
|
|
|
ret = log~open("", "System")
|
|
|
|
if ret == 0 then do
|
|
totalRecs = log~getNumber
|
|
|
|
if totalRecs < 3 then do
|
|
say "To few records (" || totalRecs || ") for this demonstration."
|
|
end
|
|
else do
|
|
-- If the user has set the overwrite option for the event log, the first
|
|
-- record is not always number 1.
|
|
firstRec = log~getFirst
|
|
|
|
-- Now calculate the record number we are going to start at.
|
|
startRec = firstRec + 3 - 1 -- Same as firstRec + 2 of course.
|
|
|
|
ret = log~readRecords("BACKWARDS", , , startRec, 3)
|
|
|
|
if ret == 0 then do
|
|
count = displayRecords(log~events)
|
|
end
|
|
else do
|
|
say "Error reading the System event log rc:" ret
|
|
end
|
|
end
|
|
end
|
|
else do
|
|
say "Error opening the System event log rc:" ret
|
|
end
|
|
|
|
-- It is always safe to invoke the close() method. If no log is open, then the
|
|
-- method does nothing.
|
|
log~close
|
|
|
|
say "=========================================================================="
|
|
say count "records read"
|
|
say
|
|
|
|
|
|
/******************************************************************************/
|
|
say "=========================================================================="
|
|
say "Going to read the complete Security event log forwards. If there are"
|
|
say "a log of records, this will produce substantial output. You can cancel"
|
|
say "if you wish."
|
|
/******************************************************************************/
|
|
ok = doPause(.true)
|
|
count = 0
|
|
|
|
if ok then do
|
|
|
|
ret = log~readRecords("FORWARDS", , "Security")
|
|
select
|
|
when when ret == 0 & log~events~items == 0 then do
|
|
-- On many systems the security log is empty.
|
|
say "The Security event log has no event records."
|
|
end
|
|
|
|
when ret <> 0 then do
|
|
say "Error reading the Security event log rc:" ret
|
|
end
|
|
|
|
otherwise do
|
|
count = displayRecords(log~events)
|
|
end
|
|
end
|
|
-- End select
|
|
end
|
|
else do
|
|
say "Skipping this demonstartion."
|
|
end
|
|
|
|
say "=========================================================================="
|
|
say count "records read"
|
|
say
|
|
|
|
|
|
/******************************************************************************/
|
|
say "=========================================================================="
|
|
say "Going to read the complete System event log in reverse chronological"
|
|
say "order. If there are a lot of records, this will produce substantial"
|
|
say "output. You can cancel if you wish."
|
|
/******************************************************************************/
|
|
ok = doPause(.true)
|
|
count = 0
|
|
|
|
if ok then do
|
|
|
|
ret = log~readRecords("BACKWARDS", , "System")
|
|
select
|
|
when when ret == 0 & log~events~items == 0 then do
|
|
say "The System event log has no event records."
|
|
end
|
|
|
|
when ret <> 0 then do
|
|
say "Error reading the System event log rc:" ret
|
|
end
|
|
|
|
otherwise do
|
|
count = displayRecords(log~events)
|
|
end
|
|
end
|
|
-- End select
|
|
end
|
|
else do
|
|
say "Skipping this demonstartion."
|
|
end
|
|
|
|
say "=========================================================================="
|
|
say count "records read"
|
|
say
|
|
|
|
|
|
/******************************************************************************/
|
|
say "=========================================================================="
|
|
say "Going to write some records to the Application event log."
|
|
say "You can skip this step if you do not want records added to"
|
|
say "your Application event log."
|
|
|
|
/* Some notes on how the event logging service works. Typically, applications
|
|
that want to write records to one of the event logs, add entries to the
|
|
registry. These registry entries control how the event logging service
|
|
handles the writing of a record.
|
|
|
|
The registry entries are written to subkeys under the Event log service.
|
|
|
|
If an application has not added the registry entries, then the event records
|
|
are *always* written to the Application log. This can not be over-ridden.
|
|
|
|
So, say there is an application, MyApplication that wants to write a record
|
|
using the source name of MyApplication to an event log. To do that the
|
|
source name must be a subkey of a logfile entry under the EventLog key in the
|
|
registry.
|
|
|
|
If MyApplication should be written to the System log the registry key must
|
|
be added like this:
|
|
|
|
HKEY_LOCAL_MACHINE
|
|
System
|
|
CurrentControlSet
|
|
Services
|
|
EventLog
|
|
System
|
|
MyApplication
|
|
Security
|
|
System
|
|
|
|
If the key does not exists, the Application event log is always used.
|
|
*/
|
|
|
|
/******************************************************************************/
|
|
ok = doPause(.true)
|
|
|
|
if ok then do
|
|
source = "MyLog"
|
|
type = 4 -- Information
|
|
category = 22
|
|
id = 33
|
|
binaryData = "01 1a ff 4b 0C"x
|
|
|
|
ret = log~write( , source, type, category, id, binaryData, "String1", "sTring2")
|
|
if ret == 0 then
|
|
say "Record" source "successfully written"
|
|
else
|
|
say "Error writing record" source "rc:" ret
|
|
|
|
-- The default type for writing a record is 'Error' This might look a little
|
|
-- scary to a user, so we will use Information for the type.
|
|
type = 4 -- Information
|
|
|
|
ret = log~write(, "Application2", type,,, "1A 1B 1C 0000 00"x, "First String", "Second String")
|
|
if ret == 0 then
|
|
say "Record Application2 successfully written"
|
|
else
|
|
say "Error writing record Application2 rc:" ret
|
|
|
|
ret = log~write(, "Security1", type,,,"1A1B1C000000"x, "Tom", "John", "Larry", "Frank")
|
|
if ret == 0 then
|
|
say "Record Security1 successfully written"
|
|
else
|
|
say "Error writing record Security1 rc:" ret
|
|
|
|
ret = log~write(,"Security2", type,,,"04 03 01 1B 1C 00 FF 00 FE 00 FD"x, "One", "Two")
|
|
if ret == 0 then
|
|
say "Record Security2 successfully written"
|
|
else
|
|
say "Error writing record Security2 rc:" ret
|
|
|
|
ret = log~write(, "System1", type,,,"1A 1B 1C 00 00 00"x, "1", "2", "3", "4")
|
|
if ret == 0 then
|
|
say "Record System1 successfully written"
|
|
else
|
|
say "Error writing record System1 rc:" ret
|
|
|
|
ret = log~write(, "System2", type,,,"1A1B1C000000"x, "House", "Apartment")
|
|
if ret == 0 then
|
|
say "Record System2 successfully written"
|
|
else
|
|
say "Error writing record System2 rc:" ret
|
|
|
|
ret = log~write(, "NotRegisteredAppliaction1", type,,,"1A1B1C0000FF00"x, "Cat", "Dog", "Rabbit")
|
|
if ret == 0 then
|
|
say "Record NotRegisteredAppliaction1 successfully written"
|
|
else
|
|
say "Error writing record NotRegisteredAppliaction1 rc:" ret
|
|
|
|
rawData = "4d 61 72 6b 20 4d 69 65 73 66 65 6c 64 0d 0a"x
|
|
ret = log~write(, "NotRegisteredAppliaction2", type,,, rawData, "ooRexx", "example")
|
|
if ret == 0 then
|
|
say "Record NotRegisteredAppliaction2 successfully written "
|
|
else
|
|
say "Error writing record NotRegisteredAppliaction2 rc:" ret
|
|
end
|
|
else do
|
|
say "Skipping this demonstartion."
|
|
end
|
|
|
|
say "=========================================================================="
|
|
say
|
|
|
|
|
|
/******************************************************************************/
|
|
say "=============================================================================="
|
|
say "The next and last demonstration will clear the Application event log."
|
|
/******************************************************************************/
|
|
|
|
backupFile = getWriteableFileName()
|
|
|
|
if backupFile == "" then do
|
|
say "Could not determine with certainty a writeable location for a backup file."
|
|
say "You may want to skip this demonstration, the log will not be backed up."
|
|
end
|
|
else do
|
|
say "The log will first be backed up to this file:"
|
|
say " " backupFile
|
|
end
|
|
|
|
say
|
|
say "You can skip this step if you do not want to clear"
|
|
say "your Application event log."
|
|
say
|
|
say "If this is the first time you ran this example, you"
|
|
say "may want to skip this test so that you can see the"
|
|
say "records written to the log in the previous demonstration."
|
|
say "(If you elected to write any records.)"
|
|
say
|
|
say "If you previously ran this example and saved the Application"
|
|
say "log, you may want to move the back up file to a different"
|
|
say "location. The same back up file name is used each time the"
|
|
say "example executes."
|
|
|
|
ok = doPause(.true)
|
|
if ok then do
|
|
if backupFile \== "" then ret = log~clear(, , backupFile)
|
|
else ret = log~clear
|
|
|
|
if ret == 0 then say "The Application event log was cleared successfully."
|
|
else say "Error clearing the Application event log rc:" ret
|
|
end
|
|
|
|
return 0 /* leave program */
|
|
|
|
::requires "winsystm.cls"
|
|
|
|
/* Routine to display the event log records */
|
|
::routine displayRecords
|
|
use strict arg records
|
|
|
|
say records~items "records read"
|
|
|
|
do record over records
|
|
say "=========================================================================="
|
|
parse var record type date time "'" sourcename"'" id userid computer "'" string "'" "'" data "'"
|
|
say 'Type : 'type
|
|
say 'Date : 'date
|
|
say 'Time : 'time
|
|
say 'Source : 'sourcename
|
|
say 'ID : 'id
|
|
say 'UserId : 'userid
|
|
say 'Computer : 'computer
|
|
say 'Detail : 'string
|
|
say 'Data : 'data
|
|
end
|
|
|
|
return records~items
|
|
|
|
/* Simple routine to do a logical into text */
|
|
::routine logicalToText
|
|
use strict arg logical
|
|
if logical then return "True"
|
|
else return "False"
|
|
|
|
/* Simple routine to pause the program */
|
|
::routine doPause
|
|
use arg confirm
|
|
|
|
say
|
|
if confirm then do
|
|
say "Continue? (y/n)"
|
|
parse lower pull answer
|
|
ok = (answer~left(1) == 'y')
|
|
end
|
|
else do
|
|
say "Press Enter to continue"
|
|
pull
|
|
ok = .true
|
|
end
|
|
say
|
|
|
|
return ok
|
|
|
|
::routine getWriteableFileName
|
|
|
|
-- Find this user's Documents directory, surely that is writeable.
|
|
|
|
shell = .oleObject~new('Shell.Application')
|
|
folderConstant = '5'~x2d()
|
|
folderObj = shell~nameSpace(folderConstant)
|
|
folderItem = folderObj~self
|
|
documentsFolder = folderItem~path
|
|
|
|
backupFile = ""
|
|
|
|
-- Check that we got a good directory
|
|
if SysIsFileDirectory(documentsFolder) then do
|
|
-- Unfortunately, we can not use a network mapped drive and it is not
|
|
-- uncommon for people to have their My Documents directory on a network
|
|
-- share.
|
|
drv = documentsFolder~left(2)
|
|
if SysDriveMap(drv, "REMOTE")~caselessWordPos(drv) == 0 then do
|
|
backupFile = documentsFolder || '\applicationBackup_01.evt'
|
|
end
|
|
end
|
|
|
|
if backupFile == "" then do
|
|
-- Keep looking, see if we can write to the current directory.
|
|
currentDir = directory()
|
|
if canWriteToDir(currentDir) then do
|
|
backupFile = currentDir || "\applicationBackup_01.evt"
|
|
end
|
|
else do
|
|
-- As a last resort, try the temp directory
|
|
tempDir = value("TEMP", , 'ENVIRONMENT')
|
|
if canWriteToDir(tempDir) then do
|
|
backupFile = tempDir || "\applicationBackup_01.evt"
|
|
end
|
|
end
|
|
end
|
|
|
|
return backupFile
|
|
|
|
::routine canWriteToDir
|
|
use strict arg dir
|
|
|
|
tmpFile = dir || '\' || "tmpFileWriteTest.deleteMe"
|
|
|
|
-- Write to the file, close it, test it, delete it.
|
|
j = lineout(tmpFile, "Delete this file if you find it")
|
|
j = lineout(tmpFile)
|
|
if SysIsFile(tmpFile) then do
|
|
answer = .true
|
|
end
|
|
else do
|
|
answer = .false
|
|
end
|
|
|
|
'del /F /Q' tmpFile '1>nul 2>&1'
|
|
|
|
return answer
|