Operating System - OpenVMS
1748006 Members
4523 Online
108757 Solutions
New Discussion юеВ

Re: DCL Script - Symbol Printing Previous Records Dates

 
Bushytea
Occasional Advisor

DCL Script - Symbol Printing Previous Records Dates

Good Morning Everyone,

I am putting together a VMS DCL script that creates a sysuaf.lis file then searches this file for specific information. Currently I am searching for Username, Password Lifetime and the users last Interactive / Non-Interactive login dates. I take this information and print it all to a TXT file.

When the information is being printed to the file the Username and Pwdlifetime fields are correct. However, the dates are wrong. The dates that are being printed are from the previous users record and not the current record being printed. It is as if the date1 and date2 symbols are not gathering the current users data but instead holding onto the previous users record data. 

I will be wanting to search for users with the DisUser flag as well.

Below is a copy of my script.

Thanks in advance.

$ set noverify
$ set noon
$!
$ set def sys$system
$ uaf := "$authorize"
$ uaf list * /full
$
$ set def DSA1:[REPORTS]
$ open/read infile sys$system:sysuaf.lis
$ open/write outfile DSA1:[REPORTS]u_with_nexp_pwd.txt
$!
$ GETREC:
$ read/end = quit infile rec
$
$ npwd = ""
$
$! CHECK FOR A USERNAME !
$ IF f$Locate("Username:",rec) .NE. f$Length(rec)
$ then usr = f$extract(10,12,rec)
$ endif
$
$! CHECK FOR LAST INTERACTIVE & NON-INTERACTIVE DATES !
$ IF (f$Locate("Last Login:",rec) .EQ. 0) .AND. (f$Locate(":",rec) .NE. 0)
$ then
$ date1 = f$extr(12,11,rec)
$ date2 = f$extr(45,11,rec)
$ endif
$
$! CHECK FOR & EXTRACT VALUE IN PWDLIFETIME: FIELD !
$ IF f$Locate("Pwdlifetime:",rec) .NE. f$Length(rec)
$ then npwd = f$extract(23,6,rec)
$ endif
$ IF npwd .EQS. "(none)" then goto writerec
$
$ goto getrec
$
$ WRITEREC:
$ SHOW SYMBOL date1
$ wrtrec = usr+" "+npwd+" "+date1+" - "+date2
$ write outfile wrtrec
$ goto getrec
$
$ QUIT:
$ close infile
$ close outfile
$ exit
[End of file]
5 REPLIES 5
Steven Schweda
Honored Contributor

Re: DCL Script - Symbol Printing Previous Records Dates

> [...] It is as if the date1 and date2 symbols are not gathering the
> current users data but instead holding onto the previous users record
> data.

   Not a surprise.  In my listing, "Pwdlifetime:" appears before "Last
Login:", so, if you "goto writerec" after you find the "Pwdlifetime:",
then you will not yet have read the (next) "Last Login:" and its
corresponding dates.

      HELP SET VERIFY

   Generally, I'd figure that I was done reading a user's info when I
saw the next "Username:" (or end-of-file).

> $ IF (f$Locate("Last Login:",rec) .EQ. 0) .AND. (f$Locate(":",rec) .NE. 0)

   What does the second F$LOCATE() do here?

Bushytea
Occasional Advisor

Re: DCL Script - Symbol Printing Previous Records Dates

That line does two things. The first locate checks if that specified string Last Login: is found. The second locate protects against empty lines. Below is another way I have coded that line but I get the same results.

$! CHECK FOR LOGIN DATE !
$ IF f$Locate("Last Login:",rec) .NE. f$Length(rec)
$       then date1 = f$extr(12,11,rec)
$       date2 = f$extr(45,11,rec)
$ endif
$

 I was thinking the same thing that based on the sysuaf file the pwdlifetime field is before the users login dates. I guess I was thinking incorrectly about the code and how it runs. I was thinking the code would run through collecting data until it reached the goto. 

Thanks,
Mike

Steven Schweda
Honored Contributor

Re: DCL Script - Symbol Printing Previous Records Dates

   Do you really want to accumulate SYSUAF.LIS files in SYS$SYSTEM?  If
I were planning to run this more than once, then I'd put a little effort
into putting the AUTHORIZE output somewhere less SYSTEM-like.  AUTHORIZE
may be too lame to give you a choice beyond "placed in the current
default directory", but you can do something with that.  For example
(assuming that SYSUAF is not already defined, and F$TRNLNM() could tell
you that):

      set default my_temp_dir
      define /user_mode sysuaf sys$system:sysuaf.dat
      mcr authorize list * /full

Steven Schweda
Honored Contributor

Re: DCL Script - Symbol Printing Previous Records Dates

> [...] I was thinking the code would run through collecting data until
> it reached the goto.

   Nah.  DCL does pretty much what you tell it to do, not what you wish
it would do (when those differ).

Hoff
Honored Contributor

Re: DCL Script - Symbol Printing Previous Records Dates

The logic in that code is incorrectly ordered; the write statements just don't happen at the appropriate part of processing each entry in SYSUAF.  As others have mentioned, debug the code. 

SYSUAF isn't always in SYS$SYSTEM.   Often times, it's not in that directory.

Protect those output files, as they contain sensitive data.

Consider writing scratch files to SYS$SCRATCH.

If you turn off procedure verification, be polite and reset it to the original value on exit.

Avoid editing the procedure to enable verification while debugging by using a procedure-specific logical name, as shown below.

Parsing the output of OpenVMS tools and utilities is not supported, subject to change and quite possibly unreliable.

Preemptively close all channels before opening them (CLOSE/NOLOG), as interrupting a DCL loop due to an error or a ^Y can have some surprising (but expected) behavior.

I'd likely use the GETUAI tool here.

Here's what I think was intended, but I'm not entirely certain...

$ set noon
$ vfy = f$verify(f$trnlnm("DEBUG_GETREC"))
$!
$ if f$trnlnm("SYSUAF") .eqs. "" then DEFINE/USER SYSUAF SYS$SYSTEM:SYSUAF.DAT
$ uaf := "$authorize"
$ uaf list * /full
$
$ close/nolog infile
$ open/read infile sysuaf.lis
$ pwdl = ""
$!
$GETREC:
$ read/end=done infile rec
$
$! are we at a new entry?  If so, dump the previous entry
$ if f$length(f$edit(rec,"COLLAPSE")) .eq. 0
$ then
$   IF pwdl .EQS. "(none)" then call writerec
$   pwdl = ""
$   goto GETREC
$ endif
$
$! fetch the username data
$ IF f$Locate("Username:",rec) .NE. f$Length(rec)
$ then
$   foo = f$edit(f$element(1,":",rec),"TRIM,COMPRESS")
$   usr = f$edit(f$element(0," ",foo),"TRIM")
$   goto GETREC
$ endif
$
$! the pwdlifetime data, of course
$ IF f$Locate("Pwdlifetime:",rec) .EQ. 0
$ then
$   foo = rec - "Pwdlifetime:"
$   foooffset = f$locate("Pwdchange",foo)
$   foo = f$extract(0,foooffset,foo)
$   pwdl = f$edit(foo,"COLLAPSE")
$   goto GETREC
$ endif
$
$! you guessed it, the last login data
$ if f$locate("Last Login:",rec) .EQ. 0
$ then
$   foo = rec - "Last Login:" - "(interactive)" - "(non-interactive)"
$   foo = f$edit(foo,"COMPRESS,TRIM")
$   lastintlogin = f$edit(f$element(0,",",foo),"TRIM")
$   lastnonintlogin = f$edit(f$element(1,",",foo),"TRIM")
$   goto GETREC
$ endif
$
$ goto GETREC
$
$WRITEREC: subroutine
$ write sys$output "matching record: <''usr'> pwdl:<''pwdl'> int:<''lastintlogin'> nonint:<''lastnonintlogin'>"
$ endsubroutine
$
$DONE:
$! dump the last record, if we have one
$ IF pwdl .EQS. "(none)" then call writerec
$
$ close/nolog infile
$ vfy = f$verify(vfy)
$ exit