/* netuser.rex * * Demonstrates how to get some information about the "Administrator" * account on the local computer. We use Reginald REXX's FUNCDEF * feature to call some Windows' APIs. */ OPTIONS "C_CALL WINFUNC" /* Register the Windows' function NetUserGetInfo() and NetApiBufferFree() */ FUNCDEF("NetUserGetInfo", "32, wstr, wstr, 32u, void stor", "Netapi32") FUNCDEF("NetApiBufferFree", "32, void", "Netapi32") /* Register a USER_INFO_3 structure. This is what we will ask NetUserGetInfo() * to return. And we will use CONVERTDATA to transfer the data in the structure * to/from our own REXX stem variable. */ FUNCDEF("USER_INFO_3", "wstr *, wstr *, 32u, 32u, wstr *, wstr *, 32u, wstr *, 32u, wstr *, wstr *, wstr *, wstr *, 32u, 32u, 32u, 32u, 32u, char *, 32u, 32u, wstr *, 32u, 32u, 32u, 32u, wstr *, wstr *, 32u") /* Call NetUserGetInfo() to retrieve the desired information about the * desired account. * * The first arg is the name of the server that the account is on. If * you omit this arg, then the local computer is used. Otherwise, it * should be the name of the server prefaced with "\\" such as * "\\MyServer". NOTE: This must be a UNICODE string if specified. * * The second arg is the name of the account. Here we pass the string * "Administrator" for that particular account. But note that this * string needs to be UNICODE (ie, "wstr" FUNCDEF type) and REXX * strings are ANSI. So we pass our REXX string to CONVERTSTR() to * convert it to UNICODE when we pass it to NetUserGetInfo(). We * also want it nul-terminated. * * The third arg is the level of information we need. By passing a 10, * we tell NetUserGetInfo() to allocate and return a structure that * has information about the account name, the password, and other * information about the account. * * The fourth arg is the name of a REXX Variable which will be set to * the address of the information that NetUserGetInfo() returns. We * will need to use CONVERTDATA to stuff this info into some REXX * compound variable. Here we let Reginald store the address in a * variable named "Address". * * NetUserGetInfo() returns 0 if success, or some error number if a * failure. */ status = NetUserGetInfo(, CONVERTSTR("Administrator", 'Z'), 3, Address) /* If the call succeeds, print the user information */ IF status == 0 THEN DO /* Stuff the returned information (USER_INFO_3 structure) into our * own REXX stem variable named MyInfo */ CONVERTDATA(Address, 'MyInfo', 'struct USER_INFO_3') /* Free the information returned by NetUserGetInfo() now that we've * transfered it to our own REXX variable */ NetApiBufferFree(Address) /* Display the information. NOTE: Some of the information is in * UNICODE string format. But REXX deals only with ANSI strings, * so when we SAY them, we use CONVERTSTR to get an ANSI version. * For some string fields, NetUserGetInfo() may nul out the field * if it has no info to return. You can check if a field has any * value by using the EXISTS() function, such as: * * IF EXISTS('MyInfo.1') THEN SAY "Account name is" MyInfo.1 * ELSE SAY "There was no Account name returned." * * But since we only want to display the strings, and don't * care if any fields aren't returned, we'll use the 'V' * flag with CONVERTSTR, and pass the quoted variable name. * In this way, if the field happens to be nul'ed out, then * CONVERTSTR will substitute an empty string. */ SAY "09"X || "Account: " CONVERTSTR('MyInfo.1', 'UV') SAY "09"X || "Password: " CONVERTSTR('MyInfo.2', 'UV') SAY "09"X || "Password age:" MyInfo.3 SAY "09"X || "Priv: " MyInfo.4 SAY "09"X || "Home dir: " CONVERTSTR('MyInfo.5', 'UV') SAY "09"X || "Comment: " CONVERTSTR('MyInfo.6', 'UV') SAY "09"X || "Flags: " MyInfo.7 SAY "09"X || "Script path: " CONVERTSTR('MyInfo.8', 'UV') SAY "09"X || "Auth. Flags: " MyInfo.9 SAY "09"X || "Full name: " CONVERTSTR('MyInfo.10', 'UV') SAY "09"X || "user comment:" CONVERTSTR('MyInfo.11', 'UV') SAY "09"X || "Parms: " CONVERTSTR('MyInfo.12', 'UV') SAY "09"X || "Workstations:" CONVERTSTR('MyInfo.13', 'UV') SAY "09"X || "Last logon: " MyInfo.14 SAY "09"X || "Last logoff: " MyInfo.15 SAY "09"X || "Expires: " MyInfo.16 SAY "09"X || "Max storage: " MyInfo.17 SAY "09"X || "Weekly units:" MyInfo.18 SAY "09"X || "Logon hours: " MyInfo.19 SAY "09"X || "PW count: " MyInfo.20 SAY "09"X || "Num logons: " MyInfo.21 SAY "09"X || "Logon server:" CONVERTSTR('MyInfo.22', 'UV') SAY "09"X || "Country code:" MyInfo.23 SAY "09"X || "Code page: " MyInfo.24 SAY "09"X || "User ID: " MyInfo.25 SAY "09"X || "Group ID: " MyInfo.26 SAY "09"X || "Profile: " CONVERTSTR('MyInfo.27', 'UV') SAY "09"X || "Home drive: " CONVERTSTR('MyInfo.28', 'UV') SAY "09"X || "Password exp:" MyInfo.29 END /* An error. Display an error message */ ELSE DO SELECT status WHEN 5 THEN str = "This script is being run under an account that has insufficient privilege for this operation." WHEN 50 THEN str = "This network request isn't supported." WHEN 53 THEN str = "The network path wasn't found." WHEN 65 THEN str = "Network access is denied." WHEN 124 THEN str = "Invalid level parameter." WHEN 234 THEN str = "More data available. Supplied buffer too small." WHEN 2102 THEN str = "Device driver not installed." WHEN 2106 THEN str = "This operation can be performed only on a server." WHEN 2123 THEN str = "Buffer too small for fixed-length data." WHEN 2138 THEN str = "The Workstation service isn't started." WHEN 2141 THEN str = "The server isn't configured for this transaction; IPC$ is not shared." WHEN 2219 THEN str = "LAN Manager can't find the user accounts database file accounts.lmx." WHEN 2221 THEN str = "Account not found." WHEN 2227 THEN str = "Server not running in user-level security." WHEN 2229 THEN str = "Error encountered in accessing accounts database." WHEN 2247 THEN str = "The user accounts database file accounts.lmx is corrupted." WHEN 2351 THEN str = "Invalid server name specified." OTHERWISE str = "Unknown error." END SAY "NetUserGetInfo() ERROR" status || ':' str END RETURN