+==========================================================+ | | | | | AdminMisc extension for Win32 Perl | | | | | | ----------------------------- | | | | by Dave Roth | | | | | | Copyright (c) 1996-1997 Dave Roth. All rights reserved. | | Courtesy of Roth Consulting | | http://www.roth.net/consult | +==========================================================+ --------------------------------------------------------------------- CHECK OUT THE FAQ!!! HTTP://WWW.ROTH.NET/PERL/ADMINMISC.HTM --------------------------------------------------------------------- Following in tradition... ***************************************************************************** * * * Use under GNU General Public License * * * * Details can be found at: * * http://www.gnu.org/copyleft/gpl.html * * * ***************************************************************************** ---------------------------------------------------------------- NOTICE: I do not guarantee ANYTHING with this package. If you use it you are doing so AT YOUR OWN RISK! ---------------------------------------------------------------- Please let me know if you hack the AdminMisc file and get it to successfully work on Win95. I N S T A L L A T I O N: ------------------------ If you are using the ActiveState Win32 Perl... 1) Copy AdminMisc.pm to the \lib\win32 directory. 2) Create a \lib\auto\win32\adminmisc directory. 3) Rename AdminMisc310.pll to AdminMisc.pll and copy it to the \lib\auto\win32\adminmisc directory. *IF you are using a build of Perl that is not compliant with the build of adminmisc that comes with this archive then you need to download a compatible version. See "Parse Exception Error" below. 4) You are all ready to use the module. Look at the test.pl script for an examples. If you are using the core distribution of Win32 Perl... 1) Copy AdminMisc.pm to the \lib\site\win32 directory. 2) Create a \lib\site\auto\win32\adminmisc directory. 3) Rename AdminMisc_Core.dll to AdminMisc.dll and copy it to the \lib\site\auto\win32\adminmisc directory. 4) You are all ready to use the module. Look at the test.pl script for an examples. What if I get a "Parse Exception Error" ? ----------------------------------------- If you run the test.pl script and it says that there was a "Parse Exception Error" then you are using a build of ActiveState's Win32 Perl that is not compatible with your particular build of AdminMisc. If this occurs you can either: a) Up or downgrade your copy of Win32 Perl to a build that will work with your copy of AdminMisc. (this seems a bit harsh since it may cause problems with other extensions). b) Download a build of AdminMisc from ftp://ftp.roth.net/pub/ntperl/adminmisc/ that matches your Win32 Perl. c) Obtain the Perl header files from ActiveState.com that match your build of Win32 Perl and recompile AdminMisc with those headers. Read more about this error on the FAQ: http://www.roth.net/perl/adminmisc.htm. Available Functions (newest functions last): ============================================ UserCheckPassword($Domain, $User, $Password) This will verify whether or not $Password is the correct password for $User on the domain $Domain ($Domain could be a server instead). If $Domain is Null ('') then the $User is assumed to be in the domain in which the account is running. If $User is Null ('') then the account to be changed is assumed to be the account which the perl script is executing under. account is running. Returns: 0 if password is incorrect 1 if password is correct UserChangePassword($Domain, $User, $OldPassword, $NewPassword) This will change the password for the user $User in domain $Domain ($Domain could be a server instead) from $OldPassword to $NewPassword. If $Domain is Null ('') then the $User is assumed to be in the domain in which the account is running. If $User is Null ('') then the account to be changed is assumed to be the account which the perl script is executing under. Returns: 0 if password was NOT changed 1 if password was changed GetLogonName() This will return the name of the user this account is logged on as. This is NOT necessarily the same as the account the perl script is running under. An account can log on as another user (known as "impersonating" another account). Returns: Name that the current account is logged in as. LogonAsUser($Domain, $User, $Password [, $LogonType) This will log the current account on under a different account. The account to log on under will be in the domain $Domain, user $User with the password $Password. If $Domain is Null ('') then the $User is assumed to be in the domain in which the account is running. $LogonType is by default (if not specified) LOGON32_LOGON_INTERACTIVE but can be any valid logon type (eg. LOGON32_LOGON_BATCH). Returns: 0 if unsuccessfull 1 if successfull LogoffAsUser([1|0]) This will log the current account out from an "impersonated" account if the current account is indeed impersonating another account. If a non 0 parameter is passed then the the logoff is forced, that is, you can force the impersonation to end even if LogonAsUser() was not called. Returns: always returns 1 CreateProcessAsUser($CommandString [, $DefaultDirectory]) This creates a new process $CommandString starting in the $DefaultDirectory (optional). The new process will be running under the account of the currently impersonated user (LogonAsUser()). There has been problems with this under NT 4.0 when the impersonated user is not an Administrator. Returns: -1 if failure otherwise the return is the OS createprocess result. UserSetAttributes($Server, $UserName, $UserFullName, $Password, $PasswordAge, $Privilege, $HomeDir, $Comment, $Flags, $ScriptPath) This performs the same function as the original UserSetAttributes() with the addition that it adds the ability to set the user's Full Name ($UserFullName). Returns: 0 if unsuccessfull 1 if successfull UserGetAttributes($Server, $UserName, $UserFullName, $Password, $PasswordAge, $Privilege, $HomeDir, $Comment, $Flags, $ScriptPath) This performs the same functino as the original UserGetAttributes() with the addition that it adds the ability to get the user's Full Name ($UserFullName). Returns: 0 if unsuccessfull 1 if successfull GetHostAddress($DNS_Name) gethostbyname($DNS_Name) GetHostName($IP_Address) gethostbyaddr($IP_Address) These four functions are the same but go by different names for the sake of sanity. You can freely mix and match any of these. Providing either an IP address or a DNS name it will return the opposite of what you provided or return a 0 if it fails. Returns: IP address, DNS name if successful. 0 if failure. DNSCache([1|0]) Sets the local DNS cache on (1) or off (0). If nothing is specified it only returns the current state of the DNS cache. Returns: 1 local DNS cache is active. 0 local DNS cache is not active. DNSCacheSize([$Size]) Sets the local DNS cache size to $Size elements (or name/ip associations). If nothing is specified then it only returns the current size of the cache. NOTE: If a number is specified then the cache will be reset and every thing in it will be lost. NOTE: The size could be anything. Don't make it too large for memory and speed sake. The default size is 600. Returns: Current size of the DNS cache. DNSCacheCount() Returns the current number of cached elements. This can not exceed the value of DNSCacheSize. Returns: Current number of cached elements. UserGetMiscAttributes($Domain, $User, \%Attributes) This will return a hash of attributes and values. The attributes are the attributes associated with the NT User account $User in the domain $Domain. If $Domain is empty then the current domain is assumed. Returns: 0 if unsuccessful 1 if successful **For details of attributes see end of this file. UserSetMiscAttributes($Domain, $User, $Attrib, $Value [, $Attrib2, $Value2]...) This will set a particular attribute $Attrib to be $Value for the NT user account $User in domain $Domain. If $Domain is empty then the current domain is assumed. Returns: 0 if unsuccessful 1 if successful **For details of attributes see end of this file. ==== Added for version 971023 ======= GetDrives([$Type]) This will return an array of drive roots. If no parameters are passed then the list will be all drives (cdroms, floppy, fixed, net, etc.). If you specify $Type the list will only contain drive roots that are of the specified type. The types are: DRIVE_FIXED DRIVE_REMOVABLE DRIVE_REMOTE DRIVE_CDROM DRIVE_RAMDISK Returns: nothing if unsuccessful array if successful GetDriveType($Drive) This will return an integer relating to a drive type of the root $Drive. Drives need to be specified as a root such as "c:\" or "a:\" (notice the need to specify the root directory). The types are: DRIVE_FIXED DRIVE_REMOVABLE DRIVE_REMOTE DRIVE_CDROM DRIVE_RAMDISK If an error occurs a 0 will be returned and if the type could not be determined (maybe a a disk is not in the drive) then a 1 will return, otherwise type drive type will return. Returns: 0 if unsuccessful 1 if unable to determine drive type if successful GetDriveSpace($Drive) This will return an array consisting of the total drive capacity and the available space on the drive. Drives need to be specified as a root such as "c:\" or "a:\" (notice the need to specify the root directory not just the drive letter). NOTE: The values returned may not be accurate if you are running on a Windows 95 OSR 1 machine due to a bug in the OS. This was fixed with OSR 2. If an UNC is used instead of $Drive then it must end with a backslash as in: \\server\share\ Returns: array ($Total, $Free) if successful nothing if unsuccessful GetDriveGeometry($Drive) This will return an array consisting of drive information in the following order: Sectors per Cluster Bytes per Sector Number of free clusters Total number of clusters If an UNC is used instead of $Drive then it must end with a backslash as in: \\server\share\ Returns: array if successful nothing if unsuccessful GetProcessorInfo() This will return a hash of processor related information. Returned values are: OEMID................OEM identifier NumOfProcessors......Number of microprocessors installed ProcessorType........Type of microprocessor ProcessorLevel.......Level of microprocessor (eg. 4=486, 5=Pentium [586], 6=Pentium Pro) ProcessorRevision....Revision of microprocessor PageSize.............Paged memory size (how much memory is paged to disk at one time) Returns: nothing if unsuccessful hash if successful GetMemoryInfo() This will return a hash of memory related information. Returned values are: Load.................Current load on memory (in percentages) Returns: nothing if unsuccessful hash if successful GetWinVersion() This will return a hash of windows versions. Returned values are: Major................Major version. Minor................Minor version. (Windows version = Major.Minor as in 3.51) Build................Build number Platform.............Platform of OS (Win32s, Win_95 or Win_NT) CSD..................Service Pack number (if any) Returns: nothing is unsuccessful hash if successful WriteINI($File, $Section, $Key, $Value) This will write the value $Value to the key $Key in the section $Section of the INI file $File. If $Value is empty then the key $Key is removed. If $Key is empty then all keys are removed from the section $Section. If $Section is empty then all sections are removed from the INI file $File. returns: 1 if successful undef if unsuccessful ReadINI($File, $Section, $Key) This will return either a scalar containing the value of $Key from the $Section section of the INI file $File. If $Key is empty then an array is returned containing all of the keys of the section $Section. If $Section is empty then an array is returned containing all of the sections in the INI file $File. Returns: array if $Section or $Key are empty and the function is successful scalar if successful nothing if unsuccessful ExitWindows($Flag) This will start the exit windows process. $Flag can be one of the following: EWX_LOGOFF......Log the user off. Applications will be told to quite so you may be prompted to save files. EWX_POWEROFF....Force the system to shutdown and power off. The system must support poweroff. (NT: calling process must have the SE_SHUTDOWN_NAME privilege) EWX_REBOOT......Shut down the system and reboot the computer. (NT: calling process must have the SE_SHUTDOWN_NAME privilege) EWX_SHUTDOWN....Shut down the system but don't reboot. (NT: calling process must have the SE_SHUTDOWN_NAME privilege) The following flag can be logically ORed with one of the above flags: EWX_FORCE.......Log the user off. Applications will be forced to exit without saving. This is a hostile way to force a log off. Returns: non zero value if successful 0 if unsuccessful GetIdInfo() This will return an array with the following information (in order): Process ID (PID)............The process ID (PID). Thread ID (TID).............The Thread ID (TID). Priority Class for PID......The priority of the process. **Currently Broken** Thread Priority.............The priority of the thread. **Currently Broken** Command Line................The command line used to start the process. Returns: array if successful GetDC() This will return a Domain Controler of the domain $Domain. If $Domain is empty then use default domain is assumed. $Domain can be either an NT domain or an NT computer. Example: GetDC("ENGINEERING"); GetDC("\\\\Server1"); GetDC("//Server1"); Returns: name of a DC for the sepecified domain if successful undef if unsuccessful GetPDC($Domain) This will return the Primary Domain Controler of the domain $Domain. If $Domain is empty then use default domain is assumed. $Domain can be either an NT domain or an NT computer. Example: GetPDC("ENGINEERING"); GetPDC("\\\\Server1"); GetPDC("//Server1"); Returns: name of the PDC for the sepecified domain if successful undef if unsuccessful GetStdHandle($Handle) This will return the win32 handle to the standard handle specified in $Handle. Possible options for $Handle are: STD_INPUT_HANDLE STD_OUTPUT_HANDLE STD_ERROR_HANDLE Returns: Win32 handle if successful undef if unsuccessful SetPassword($Server, $User, $Password) This will set the user $User password to $Password. This assumes that the calling process has administrative rights on the target server/domain. Limitations on accounts may restrict the setting of passwords, for example, setting a password to empty ('') may be restricted if blank passwords are not allowed in the domain. Returns: 1 if successful 0 if not successful GetTOD($Server) This will retrieve the time of day from the computer $Server. If $Server is empty then the current computer is used. The return value is in the same format that time() returns. Returns: value if successful undef if not successful RenameUser($Server, $User, $NewUser) This will rename the user account $User to $NewUser. All groups will reflect the new name. The command will be sent to $Server to be processed. If $Server is a domain name then it will find the PDC for that domain. If $Server is a computer name in the format of \\server or //server then it will execute the command on that computer. If $Server is blank then it will be run on the local machine. Returns: 1 if successful 0 if not successful ScheduleAdd($Machine, $Time, $DOM, $DOW, $Flags, $Command) This will schedule $Command to run at $Time on the day of the month determined by the bitmask $DOM and the day of the week determined by the bitmask $DOW. The scheduled job will be added with the flags specified in $Flags. $DOM........A bitmask where each bit represents a day of the month. For example: 2**4 | 2**17 would represent the 4th and 17th. $DOW........A bitmask where each bit represents a day of the week starting with Monday as bit 0. The following constants are defined: MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY These constants can be ORed together. $Flags......A bitmask representing flags: JOB_RUN_PERIODICALLY....The job will run on every DOW and DOM scheduled. If this bit is not set then the job will run once for each DOM and DOW set. JOB_ADD_CURRENT_DATE....The job will run at the next $Time. If the $Time has already passed it will schedule to run at $Time tomorrow. JOB_EXEC_ERROR..........This bit is set when the last time the particular job ran it errored. This is a read only bit. JOB_RUNS_TODAY..........This bit is set when the job's time has yet to pass for the current day. This is set even if the job is not scheduled to run on the current day. JOB_NONINTERACTIVE......This bit is set if the job will not run allowing for interaction with the desktop. $Command....This is any command that will be run. Returns: job number if successful undef if not successful ScheduleDel($Machine, $JobNumber [, $MaxJobNumber]) This will delete the job number $JobNumber on the machine $Machine. If the third parameter is specified all jobs between and including $JobNumber and $MaxJobNumber will be deleted. Returns: 1 if successful 0 if not successful ScheduleList($Machine [, \%List]) This will return the total number of jobs scheduled to run on $Machine. If a hash reference is specified as a second parameter then a hash of hashes will be populated with information about each job. Returns: total number of jobs if successful undef if not successful ScheduleGet($Machine, $JobNumber, \%JobInfo) This will retrieve information about a particular scheduled job on $Machine. The information is stored in the hash %JobInfo. Returns: 1 if successful 0 if not successful GetFileInfo($File, \%Info) This will return a 1 if there is information available for the file $File. If the function is successful then the hash %Info will be populated with file information that is available on that file. Information returned in the hash include copyright, company, original filename, etc. Returns: 1 if successful 0 if not successful GetEnvVar($Name [, $Type]) This will return the value of the environmental variable $Name. If $Type is specified it can be one of: ENV_SYSTEM........Specifies that $Name will be a system environmental variable. (default if $Type is not specified) ENV_USER..........Specifies that $Name will be a user environemental variable. Returns: value of the environmental variable if successful undef if not successful SetEnvVar($Name, $Value [, $Type [, $Timeout]]) This will set an environmental variable $Name to $Value. This function will set the variable (creating it if $Name does not exist). The new value will be set globally so all applications will be able to use it, unlike setting $ENV{xxx} -- which sets the variable for the current process and any children it spawns afterwards. If $Timeout is specified then the function will wait up to $Timeout seconds for other applications to become aware that the environment has changed. If the function timesout some applications may not be aware of the variable changes. If $Type is specified it can be one of: ENV_SYSTEM........Specifies that $Name will be a system environmental variable. (default if $Type is not specified) ENV_USER..........Specifies that $Name will be a user environemental variable. This function is the equivalent to setting an environental variable in the control panel's system applet. NOTE: Your script will not see the new value. For that you should set $ENV{xxx}. Returns: 1 if setting the variable was successful 0 if not successful DelEnvVar($Name [, $Type [, $Timeout]]) This will delete an environmental variable $Name. Thi affect of this function will be seen globally, not only the currently running process. If $Timeout is specified then the function will wait up to $Timeout seconds for other applications to become aware that the environment has changed. If the function timesout some applications may not be aware of the variable changes. If $Type is specified it can be one of: ENV_SYSTEM........Specifies that $Name will be a system environmental variable. (default if $Type is not specified) ENV_USER..........Specifies that $Name will be a user environemental variable. This function is the equivalent to setting an environental variable in the control panel's system applet. NOTE: Your script will not see the new value. For that you should set $ENV{xxx}. Returns: 1 if deleting the variable was successful 0 if not successful ===== The following has been updated ===== CreateProcessAsUser($CommandString [, $DefaultDirectory] [, %Config]) This will create a process that will be running under the account that you are impersonating with LogonAsUser(). $CommandString......The full command line of the processes to run. $DefaultDirectory...The default directory that the process runs in. %Config.............A hash of values that specify a configuration the process is to run with. The %Config hash can consist of any of the following: Title...............The title of the processes window. Desktop.............A virtual desktop. Leave this blank if you are not familiar with it. The default is "winsta0\default". X...................The X coordinate of the upper left corner of the processes window. Y...................The Y corrdinate of the upper left corner of the processes window. XSize...............The width of the processes window (in pixels). YSize...............The height of the processes window (in pixels). XBuffer.............Number of chars the X buffer should be. This applies only to console applications. YBuffer.............Number of chars to Y buffer should be. This applies only to console applications. Fill................The color to fill the window. This applies only to console applications. Possible values can be logically ORed together: BACKGROUND_RED BACKGROUND_BLUE BACKGROUND_GREEN BACKGROUND_INTENSITY FOREGROUND_RED FOREGROUND_GREEN FOREGROUND_BLUE FOREGROUND_INTENSITY Priority............The priority to run the process under. It can use one of the following: HIGH_PRIORITY_CLASS IDLE_PRIORITY_CLASS NORMAL_PRIORITY_CLASS REALTIME_PRIORITY_CLASS Flags...............Flags specifying process startup options. Some of these can be logically ORed together: CREATE_DEFAULT_ERROR_MODE CREATE_NEW_CONSOLE CREATE_NEW_PROCESS_GROUP CREATE_SEPARATE_WOW_VDM CREATE_SUSPENDED CREATE_UNICODE_ENVIRONMENT DEBUG_PROCESS DEBUG_ONLY_THIS_PROCESS DETACHED_PROCESS; ShowWindow..........State of the processes window during startup. Possible values: SW_HIDE SW_MAXIMIZE SW_MINIMIZE SW_RESTORE SW_SHOW SW_SHOWDEFAULT SW_SHOWMAXIMIZED SW_SHOWMINIMIZED SW_SHOWMINNOACTIVE SW_SHOWNA SW_SHOWNOACTIVATE SW_SHOWNORMAL StdInput StdOutput StdError............Specifies which handle to use for standard IN, OUT and ERROR. If one of these is specified *ALL MUST* be specified. You can use GetStdHandle() to retrieve the handle for the current standard handle. Inherit.............Specifies to inherit file handles. Directory...........Specifies a default directory. This is the same attribute as the $DefaultDirectory. This function requires the calling process to have the following rights assigned: Privilege Display Name ------------------------------------------------------ SeTcbPrivilege Act as part of the operating system SeAssignPrimary Replace a process level token SeIncreaseQuota Increase quotas returns the process id (PID) if successful undef if unsuccessful ============================================================ ==== Misc Attribute List ============================================================ The following attributes are used with the UserGet/SetMiscAttributes() method: user_name Specifies the name of the user account. This is a read only value and can not be set by this function. user_password Specifies a one-way encrypted LAN Manager 2.x-compatible password. This is not shown due to the Win32 API. It is here for backward compatibility with LAN Manager. For all practicle purposes this attribute is ignored. This can not be set by this function. user_password_age Specifies the number of seconds elapsed since the password attribute was last changed. The NetUserAdd and NetUserSetInfo functions ignore this attribute. This is a read only value and can not be set by this function. user_priv One of three values specifying the level of privilege assigned the user account. For the NetUserAdd function, this attribute must be USER_PRIV_USER. This is a read only value and can not be set by this function. This can be one of the following values: Value Meaning ------------------- ------- USER_PRIV_GUEST Guest USER_PRIV_USER User USER_PRIV_ADMIN Administrator user_home_dir The path of the home directory for the user specified. user_comment The user account comment. user_flags Contains values that determine several features. This attribute can be any of the following values: Value Meaning ------------------- ------- UF_SCRIPT The logon script executed. This value must be set for LAN Manager 2.0 or Windows NT. UF_ACCOUNTDISABLE The user's account is disabled. UF_HOMEDIR_REQUIRED The home directory is required. This value is ignored in Windows NT. UF_PASSWD_NOTREQD No password is required. UF_PASSWD_CANT_CHANGE The user cannot change the password UF_LOCKOUT The account is currently locked out. This value can be cleared to unlock a previously locked account. This value, however, cannot be used to lock a previously locked account. UF_DONT_EXPIRE_PASSWD Represents the password, which should never expire on the account. This value is valid only for Windows NT. The following values describe the account type. Only one value can be set. This is a read only value. UF_NORMAL_ACCOUNT This is a default account type that represents a typical user. UF_TEMP_DUPLICATE_ACCOUNT This is an account for users whose primary account is in another domain. This account provides user access to this domain, but not to any domain that trusts this domain. The User Manager refers to this account type as a local user account. UF_WORKSTATION_TRUST_ACCOUNT This is a computer account for a Windows NT Workstation or Windows NT Server that is a attribute of this domain. UF_SERVER_TRUST_ACCOUNT This is a computer account for a Windows NT Backup Domain Controller that is a attribute of this domain. UF_INTERDOMAIN_TRUST_ACCOUNT This is a permit to trust account for a Windows NT domain that trusts other domains. user_script_path The path of the user's logon script, .CMD, .EXE, or .BAT file. user_auth_flags Specifies an unsigned long integer that contains values that specify the user's operator privileges. This is a read only value and should *NOT* be changed. The value is based on the local group attributeship. If the user is a attribute of Print Operations, AF_OP_PRINT is set. If the user is a attribute of Server Operations, AF_OP_SERVER is set. If the user is a attribute of the Account Operations, AF_OP_ACCOUNTS is set. AF_OP_COMM is never set. This attribute can be one of the following values: Value Meaning ------------------- ------- AF_OP_PRINT The print operator privilege is enabled. AF_OP_COMM The communiations operator privilege is enabled. AF_OP_SERVER The server operator privilege is enabled. AF_OP_ACCOUNTS The accounts operator privilege is enabled. user_full_name The full name of the user. user_usr_comment The user comment. user_parms This is set aside for use by applications. This string can be a null string, or it can have any number of characters before the terminating null character. Microsoft products use this attribute to store user configuration information. Do not modify this information. user_workstations The names of workstations from which the user can log on. As many as eight workstations can be specified; the names must be separated by commas (,). A null string indicates that there is no restriction. To disable logons from all workstations to this account, set the UF_ACCOUNTDISABLE value in the flags attribute. user_last_logon Specifies when the last logon occurred. This value is stored as the number of seconds elapsed since 00:00:00, January 1, 1970. This attribute is read only. This attribute is maintained separately on each Backup Domain Controller in the domain. To get an accurate value, each BDC in the domain must be queried, and the largest value is used. user_last_logoff Specifies when the last logoff occurred. This value is stored as the number of seconds elapsed since 00:00:00, January 1, 1970. A value of zero means that the last logoff time is unknown. This attribute is read only. in NetUserAdd and NetUserSetInfo calls. This attribute is maintained separately on each Backup Domain Controller in the domain. To get an accurate value, each BDC in the domain must be queried and the largest value is used. user_acct_expires Specifies when the account will expire. This value is stored as the number of seconds elapsed since 00:00:00, January 1, 1970. A value of TIMEQ_FOREVER indicates that the account never expires. user_max_storage Specifies the maximum amount of disk space the user can use. Use the value specified in USER_MAXSTORAGE_UNLIMITED to use all available disk space. user_units_per_week Specifies the number of equal-length time units into which the week is divided. This attribute uses these time units to compute the length of the bit string in the USER_LOGON_HOURS attribute. This value must be UNITS_PER_WEEK for LAN Manager 2.0. This attribute is read only. For Windows NT services, the units must be one of the following: SAM_DAYS_PER_WEEK, SAM_HOURS_PER_WEEK, or SAM_MINUTES_PER_WEEK. user_logon_hours Points to a 21-byte (168 bits) bit string that specifies the times during which the user can log on. Each bit represents a unique hour in the week. The first bit (bit 0, word 0) is Sunday, 0:00 to 0:59; the second bit (bit 1, word 0) is Sunday, 1:00 to 1:59; and so on. If this attribute is null (null, not zero) when used with UserSetMiscAttributes() means that no change is to be made. user_bad_pw_count Specifies the number of times the user tried to log on to this account using an incorrect password. A value of 0xFFFFFFFF indicates that the value is unknown. This attribute is read only. This attribute is maintained separately on each Backup Domain Controller in the domain. To get an accurate value, each BDC in the domain must be queried, and the largest value is used. user_num_logons Counts the number of successful times the user tried to log on to this account. A value of 0xFFFFFFFF indicates that the value is unknown. This attribute is read only. This attribute is maintained separately on each Backup Domain Controller in the domain. To get an accurate value, each BDC in the domain must be queried, and the attribute uses the sum of the values. user_logon_server The name of the server to which logon requests are sent. Servernames should be preceded by two backslashes (\\). When a servername is represented by an asterisk (\\*), the logon request can be handled by any logon server. A null string indicates that requests are sent to the domain controller. This attribute is read only. For Windows NT Servers, UserGetMiscAttributes() will return \\*. user_country_code The country code for the user's language of choice. Windows NT does not use the country code. user_code_page The code page for the user's language of choice. Windows NT does not use the code page.