Web Listing 1: Logonlogoff.cmd @Echo Off setlocal :: This is a list of servers that store the event-log dumps created :: by logdump.cmd and stored in .zip archives. Set serverlist=SERVER1 SERVER2 SERVER3 :: Ensure that all three parameters have been specified. IF #%4#==## goto :syntax :: Clear out and create a temporary directory location. set logonlogofftemp=%temp%\logonlogoff IF EXIST %temp%\logonlogoff rmdir /s /q %logonlogofftemp% md %logonlogofftemp% :: Store parameter information. :: BEGIN CALLOUT A set start_date=%1 set end_date=%2 set userid=%3 set logtype=win2k if /I #%4#==#NT# set logtype=NT :: END CALLOUT A :: Delete the existing output file if it already exists. if exist %userid%.csv del /q %userid%.csv :: Get the current year from the output of "date /t" and store in curr_year. for /f "tokens=3 delims=/" %%i in ('date /t') do set curr_year=%%i :: Parse Dates set start_month= set start_day= set start_year= set end_month= set end_day= set end_year= :: Tokenize the specified start and end dates passed into the script. :: BEGIN CALLOUT B for /f "tokens=1-3 delims=/\" %%i in ('echo %start_date%') do set start_month=%%i& set start_day=%%j& set start_year=%%k for /f "tokens=1-3 delims=/\" %%i in ('echo %end_date%') do set end_month=%%i& set end_day=%%j& set end_year=%%k :: END CALLOUT B :: Make sure the user has specified dates in the specified format. if not defined start_year goto :syntax if not defined end_year goto :syntax :: If the specified year is later than the current year, we don't have logs for it yet. Show Syntax. if %start_year% GTR %curr_year% goto :syntax if %end_year% GTR %curr_year% goto :syntax :: Remove any leading 0s in the start and end days. if %start_day:~0,1% EQU 0 set start_day=%start_day:~1,1% if %end_day:~0,1% EQU 0 set end_day=%end_day:~1,1% :: Check for leap year and adjust accordingly for the start date. set isStartLeapYear= call :isleapyear %start_year% if NOT defined isleapyear goto :checkstartvalid :: If we get here, the start year must be a leap year. set isStartLeapYear=TRUE :checkstartvalid set no_days=31 :: If the month is April, June, September, or November, :: the number of days should be 30. if %start_month% EQU 4 set no_days=30 & goto :check_days if %start_month% EQU 6 set no_days=30 & goto :check_days if %start_month% EQU 9 set no_days=30 & goto :check_days if %start_month% EQU 11 set no_days=30 & goto :check_days :: Check for the special condition of February if year is a leap year. if NOT %start_month% EQU 2 goto :check_days set no_days=28 if defined isStartLeapYear set no_days=29 :: Make sure the date makes sense. If the day of the month is :: greater than the number of days for a given month, then :: the date is invalid. Display syntax. :check_days IF %start_day% GTR %no_days% goto :syntax :: Check for leap year and adjust accordingly for the end date. set isEndLeapYear= call :isleapyear %end_year% if NOT defined isleapyear goto :checkendvalid :: If we get here, the end year must be a leap year. set isEndLeapYear=TRUE :checkendvalid set no_days=31 if %end_month% EQU 4 set no_days=30 & goto :check_days2 if %end_month% EQU 6 set no_days=30 & goto :check_days2 if %end_month% EQU 9 set no_days=30 & goto :check_days2 if %end_month% EQU 11 set no_days=30 & goto :check_days2 :: Check for the special condition of February, if year is a leap year. if NOT %end_month% EQU 2 goto :check_days2 set no_days=28 if defined isEndLeapYear set no_days=29 :check_days2 IF %end_day% GTR %no_days% goto :syntax :: Now that both dates seem valid, perform one last check. :: Is the end date later than the start date? if %end_year% GTR %start_year% goto :proceed if %end_year% LSS %start_year% goto :syntax :: If you get here, the year must be the same for start and :: end dates. You then need to check that the end month :: is later than the start month. if %end_month% GTR %start_month% goto :proceed if %end_month% LSS %start_month% goto :syntax :: If the user wants logs from the same year and month, :: ensure that the end day is after the :: start day or else output the syntax. if %end_day% LSS %start_day% goto :syntax :proceed @CLS @ECHO. @ECHO You have requested to generate a logon/logoff report for @ECHO %userid% for the period %start_date% to %end_date% @ECHO. @ECHO If successful, the file %userid%.csv will be created in @ECHO the current directory. @ECHO. @ECHO Please wait while I process your request... @ECHO. :: Extract the .zip files from the server so that you can :: process the logs. :: BEGIN CALLOUT C set processmonth=%start_month% set processyear=%start_year% if %processmonth:~0,1% EQU 0 set processmonth=%processmonth:~1,1% if %end_month:~0,1% EQU 0 set end_month=%end_month:~1,1% :extractzips set stop= :: If the month and year to process is the same as the end year, do this :: one last time, then stop. if %processmonth%%processyear% EQU %end_month%%end_year% set stop=true if %processmonth% GEQ 10 goto :copyandextract :: Add a leading 0 to the month. set processmonth=0%processmonth% for %%i in (%serverlist%) do call :copyandextract %%i goto donecopy :copyandextract set server=%1 :: Check whether logs are available for the month and year you want to process. if NOT exist \\%server%\c$\logs\seclog\%server%_seclog_%processmonth%_%processyear%.zip ECHO %server% Log for %processmonth%\%processyear% doesn't exist & goto :EOF ECHO Processing %server%_seclog_%processmonth%_%processyear%.zip... copy \\%server%\c$\logs\seclog\%server%_seclog_%processmonth%_%processyear%.zip %logonlogofftemp% > NUL unzip %logonlogofftemp%\%server%_seclog_%processmonth%_%processyear%.zip -d %logonlogofftemp% > NUL goto :EOF :donecopy :: If stop was set above, you are done. if defined stop goto :searchlogonlogoff :: Increment to next month. if %processmonth:~0,1% EQU 0 set processmonth=%processmonth:~1,1% set /a processmonth=processmonth+1 :: If you have passed December (month 12), you need to process the file for January of the following year, which means you need to increment the year by one and reset the month to 1. IF %processmonth% GTR 12 set /a processyear=processyear+1 IF %processmonth% GTR 12 set processmonth=1 goto :extractzips :: END CALLOUT C :: Search for the Logon (event ID 528) and Logoff (event ID 538) :: events for the specified user. :searchlogonlogoff :: Eliminate log files that are out of the desired date range. :: First, put the start month and end month in a two-digit format that's compliant with the naming :: convention of our log file dumps. To do so, check whether the number is less than 10; if it is, add a leading 0. if %start_month:~0,1% EQU 0 set start_month=%start_month:~1,1% if %end_month:~0,1% EQU 0 set end_month=%end_month:~1,1% if %start_month% GEQ 10 goto :checkendfilter set start_month=0%start_month% :checkendfilter if %end_month% GEQ 10 goto :filterlogs set end_month=0%end_month% :filterlogs ECHO Removing unnecessary temporary log files... :: For each log file that's in the same month as the start and end month and year, check whether the date :: is outside the range for your search and delete the files that are. :: BEGIN CALLOUT D for /f %%i in ('dir /b %logonlogofftemp%\*.txt ^| find /I "DC_%start_month%" ^| find /I "_%start_year%"') do call :deleteunwanted %%i start for /f %%i in ('dir /b %logonlogofftemp%\*.txt ^| find /I "DC_%end_month%" ^| find /I "_%end_year%"') do call :deleteunwanted %%i end :: END CALLOUT D :: Combine the log files that contain the specified user into one file to process. ECHO Filtering log files (this may take a while)... for /f %%i in ('dir /b %logonlogofftemp%\*.txt') do type %logonlogofftemp%\%%i | find /I "%userid%" >> %logonlogofftemp%\%userid%.log :: Split the file that now contains only log entries with the specified username into two files, one containing :: only logon entries and the other containing only logoff entries. type %logonlogofftemp%\%userid%.log | find ",528," > %logonlogofftemp%\%userid%_logon.log type %logonlogofftemp%\%userid%.log | find ",538," > %logonlogofftemp%\%userid%_logoff.log :: Output file header information to output file. ECHO Username,Date and Time,Logon/Logoff,Workstation >> %userid%.csv for /f "tokens=6,8,9 delims=," %%i in (%logonlogofftemp%\%userid%_logon.log) do call :outputreport "%%i" %%j Logon "%%k" for /f "tokens=6,8 delims=," %%i in (%logonlogofftemp%\%userid%_logoff.log) do call :outputreport "%%i" %%j Logoff :done ECHO Cleaning Up... :: Delete the log files that have been extracted to the temporary location. RMDIR /S /Q %logonlogofftemp% ECHO. ECHO The report has been created as %userid%.csv endlocal goto :EOF :: Output report to user log file. :outputreport set date_time=%1 set the_user=%2 set logon_logoff=%3 set date_time=%date_time:"=% :: Because you only want the date and time, not the day (i.e., Tue), remove the first four characters of the date_time variable (the day and the space before the date). set date_time=%date_time:~4,100% set t_month= set t_date= set t_time= set t_year= set logon_wks= :: When outputing a Logon entry, output the workstation the user logged on from. if /I "%logon_logoff%"=="Logon" set logon_wks=%4 :: Tokenize the date and time into its different parts. for /f "tokens=1-4" %%j in ('echo %date_time%') do set t_month=%%j& set t_date=%%k& set t_time=%%l& set t_year=%%m :: Translate the months into a numeric value. IF /I "%t_month%"=="Jan" set t_month=01 IF /I "%t_month%"=="Feb" set t_month=02 IF /I "%t_month%"=="Mar" set t_month=03 IF /I "%t_month%"=="Apr" set t_month=04 IF /I "%t_month%"=="May" set t_month=05 IF /I "%t_month%"=="Jun" set t_month=06 IF /I "%t_month%"=="Jul" set t_month=07 IF /I "%t_month%"=="Aug" set t_month=08 IF /I "%t_month%"=="Sep" set t_month=09 IF /I "%t_month%"=="Oct" set t_month=10 IF /I "%t_month%"=="Nov" set t_month=11 IF /I "%t_month%"=="Dec" set t_month=12 :: If logon_wks is not defined, then this is probably a logoff event, so the script goes directly to outputting :: to the log. IF NOT DEFINED logon_wks goto :output_to_log_logoff :: Derive the workstation the user logged on from depending on the OS of the server the logs were dumped from. IF #%logtype%#==#win2k# goto :win2klogtype :NTlogtype for /f "tokens=9 delims=:" %%a in ('echo %logon_wks%') do set logon_wks=%%a set logon_wks=%logon_wks:"=% set logon_wks=%logon_wks: =% set logon_wks=%logon_wks:\=% goto :output_to_log_logon :win2klogtype :: Interactive logons don't contain the workstation name, so you need to know whether this is an interactive :: or network logon. for /f "tokens=2 delims=)" %%k in ('echo %logon_wks%') do set logontype=%%k set logontype=%logontype:~0,1% IF %logontype% EQU 2 goto :interactive :: The workstation name is specified after the double backslash '\\' in the current value of logon_wks. :: for /f "tokens=2 delims=\" %%k in ('echo %logon_wks%') do set logon_wks=%%k :: Remove any double quotes in %logon_wks% so that it outputs correctly. set logon_wks=%logon_wks:"=% goto :output_to_log_logon :interactive set logon_wks=Interactive :output_to_log_logon echo %the_user%,%t_month%/%t_date%/%t_year% %t_time%,%logon_logoff%,%logon_wks% >> %userid%.csv goto :EOF :: Output to log file. :output_to_log_logoff echo %the_user%,%t_month%/%t_date%/%t_year% %t_time%,%logon_logoff% >> %userid%.csv goto :EOF :: Deletes unwanted log files. :deleteunwanted set checkfile=%1 set start_end=%2 set checkfiledate= :: Get the file date from the filename. for /f "Tokens=4 delims=_" %%j in ('echo %checkfile%') do set checkfiledate=%%j if NOT defined checkfiledate goto :EOF :: Remove leading 0 to get ready for date comparison. if %checkfiledate:~0,1% EQU 0 set checkfiledate=%checkfiledate:~1,1% if /I "%start_end%"=="start" goto checkstart if /I "%start_end%"=="end" goto checkend goto :EOF :checkstart if %checkfiledate% LSS %start_day% del /q "%logonlogofftemp%\%checkfile%" goto :EOF :checkend if %checkfiledate% GTR %end_day% del /q "%logonlogofftemp%\%checkfile%" goto :EOF :: Syntax output :syntax ECHO. ECHO SYNTAX: logonlogoff.cmd ^ ^ ^ ^ ECHO log_type specifies type Operating system of the servers ECHO the logs we are processing are dumped from and can be ECHO the values NT or win2k, default is win2k ECHO. ECHO EXAMPLE: logonlogoff.cmd 01/02/2001 01/15/2001 010626 win2k ECHO. goto :EOF :: Checks whether the specified year is a leap year. :: BEGIN CALLOUT E :isleapyear set year=%1 set test= set product= set isLeapYear= set /a test = year / 4 set /a product = test * 4 IF NOT %year% EQU %product% goto :EOF set /a test = year / 400 set /a product = test * 400 IF %year% EQU %product% set isLeapYear=TRUE & goto :EOF set /a test = year / 100 set /a product = test * 100 IF NOT %year% EQU %product% set isLeapYear=TRUE goto :EOF :: END CALLOUT E