Password Expiration Control (PWDEXPMON.PGM.CLLE)

This is the "engine" part, a simple CL wrapper that takes the DAYS parameter from the command and hands it off to the real worker bee: an SQLRPGLE program. If you're new to CL (Control Language), think of it as the glue that ties commands to programs on IBM i. We'll keep this technical, focused on IBM i programming, and break it down line by line.

Quick Overview of the Program's Role

This CL program, named PWDEXPMON (same as the command for simplicity), acts as a middleman. It receives the DAYS value (e.g., 7 for a week ahead), calls the SQLRPGLE program to do the heavy lifting like querying user profiles, and handles any errors gracefully. Why a wrapper? CL is great for error monitoring and messaging, while RPGLE shines at SQL database work.

This setup keeps things modular and easy to maintain.

Here's the code for reference:

/* --------------------------------------------------------------------- */
/* Program: PWDEXPMON - Password Expiration Monitor CL Wrapper           */
/* --------------------------------------------------------------------- */
/* Description: CL wrapper program for password expiration monitoring.   */
/* Called by the PWDEXPMON command and invokes the                       */
/* PWDEXPILE SQLRPGLE program that performs the actual                   */
/* monitoring. Provides error handling and completion                    */
/* messaging.                                                            */
/*                                                                       */
/* Purpose: Production utility demonstrating:                            */
/* - CL wrapper program pattern                                          */
/* - Parameter passing to SQLRPGLE program                               */
/* - Error handling with MONMSG                                          */
/* - Completion and error messaging                                      */
/* - Command-to-program interface                                        */
/*                                                                       */
/* Features:                                                             */
/* - Accepts warning days parameter with validation                      */
/* - Calls PWDEXPILE SQLRPGLE program                                    */
/* - Comprehensive error handling                                        */
/* - Success/failure messaging                                           */
/* - Clean program termination                                           */
/* - Parameter validation (1-999 days)                                   */
/*                                                                       */
/* Usage: CALL PWDEXPMON PARM(7) - Check 7 days ahead                    */
/* CALL PWDEXPMON PARM(14) - Check 14 days ahead                         */
/*                                                                       */
/* Parameters:                                                           */
/* - &PERIOD: *DEC(3 0) - Number of days to look ahead for expiring      */
/* passwords (valid range: 1-999)                                        */
/*                                                                       */
/* Called By: PWDEXPMON command                                          */
/* Calls: PWDEXPILE SQLRPGLE program                                     */
/*                                                                       */
/* Compiler Options:                                                     */
/* CRTBNDCL PGM(library/PWDEXPMON) SRCFILE(library/QCLLESRC)             */
/* SRCMBR(PWDEXPMON)                                                     */
/*                                                                       */
/* Reference:                                                            */
/* - IBM i Security Reference                                            */
/* - Password Policy Management                                          */
/* - https://www.nicklitten.com/IBM-i-password-expiration-monitoring/    */
/*                                                                       */
/* Modification History:                                                 */
/* V.000 2026-02-03 | Nick Litten | Initial creation                     */
/* V.001 2026-04-04 | Nick Litten | Standardized header block            */
/* V.002 2026-04-18 | Nick Litten | Applied comment standards            */
/* V.003 2026-05-28 | Nick Litten | Enhanced error handling and          */
/* parameter validation                                                  */
/* --------------------------------------------------------------------- */

PGM PARM(&PERIOD &IFSFILE)

DCLPRCOPT LOG(*NO) DFTACTGRP(*NO) ACTGRP(*CALLER)

COPYRIGHT TEXT('V.003 - Password Expiration Monitor CL Wrapper')

DCL VAR(&PERIOD) TYPE(*CHAR) LEN(6)
DCL VAR(&IFSFILE) TYPE(*CHAR) LEN(256)

DCL VAR(&MSGID) TYPE(*CHAR) LEN(7)
DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(512)
DCL VAR(&MSGF) TYPE(*CHAR) LEN(10)
DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10)

/* --------------------------------------------------------------------- */
/* Monitor for errors */
/* --------------------------------------------------------------------- */
MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))

SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) +
TOPGMQ(*EXT) MSGTYPE(*STATUS) +
MSGDTA('Password expiration monitoring for users +
expiring with a' *bcat &PERIOD)

SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) +
TOPGMQ(*EXT) MSGTYPE(*STATUS) +
MSGDTA('IFS output file path: ' *cat &IFSFILE)

CALL PGM(PWDEXPILE) PARM(&PERIOD &IFSFILE)

SNDPGMMSG MSG('Password expiration monitoring completed +
successfully') TOPGMQ(*EXT) MSGTYPE(*COMP)

GOTO CMDLBL(ENDPGM)

/* --------------------------------------------------------------------- */
/* Error handling */
/* --------------------------------------------------------------------- */
ERROR:
RCVMSG MSGTYPE(*EXCP) MSGDTA(&MSGDTA) MSGID(&MSGID) +
MSGF(&MSGF) MSGFLIB(&MSGFLIB)

SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) +
MSGDTA('PWDEXPMON failed: ' *CAT &MSGID *CAT ' - ' +
*CAT &MSGDTA) MSGTYPE(*ESCAPE)

/* --------------------------------------------------------------------- */
/* Program end */
/* --------------------------------------------------------------------- */
ENDPGM:
ENDPGM

How It Works

1. Program Entry (lines 52-59)

  • Accepts two parameters: &PERIOD (6-char string for days ahead) and &IFSFILE (256-char IFS file path)
  • Configured with DCLPRCOPT to run in caller's activation group (not default)

2. Error Monitoring Setup (line 69)

3. Status Messages (lines 71-78)

  • Sends two status messages to the external message queue:
    • First message shows the monitoring period
    • Second message displays the IFS output file path

4. Core Processing (line 80)

  • CALL PGM(PWDEXPILE) invokes the SQLRPGLE program that performs the actual password expiration checking
  • Passes both parameters to the RPGLE program

5. Success Path (lines 82-85)

  • Sends completion message if PWDEXPILE succeeds
  • Jumps to ENDPGM label for clean exit

6. Error Handling (lines 90-96)

  • ERROR: label receives control if any error occurs
  • RCVMSG retrieves the exception message details
  • Sends an escape message with the error information, causing the program to fail visibly

Design Pattern

This is a classic CL wrapper pattern used in IBM i development:

  • Separation of concerns: CL handles messaging and error routing; RPGLE handles business logic
  • Error isolation: Catches errors from the called program and formats them appropriately
  • User feedback: Provides status updates during execution
  • Command interface: Designed to be called by the PWDEXPMON command

This IBM-i Control Language program ensures users get clear feedback about what's happening and meaningful error messages if something fails.

Compile this with CRTCLPGM PGM(PWDEXPMON) SRCFILE(YOURLIB/QCLLESRC), and attach it to your command via CRTCMD's PGM parameter.

This CL wrapper shows how IBM i keeps admin tasks reliable and scriptable. If you're coding similar tools, start simple like this and build up. Got questions on the SQLRPGLE part? Let me know, we can dive deeper next time. Stay coding!

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
>