Link to home
Start Free TrialLog in
Avatar of nkanand
nkanand

asked on

Any way to get home directories of all user's on a windows system

Hi All,

Is there any way to get home directories of all user accounts on Windows machine.

by default they are under: C:\Documents and Settings\<account name>.

Any help will be greatly appreciated.

I am looking for something that can be written in C++ or C code

Regards,
Avatar of jkr
jkr
Flag of Germany image

Use 'NetUserEnum()' and 'NetUserGetInfo()', e.g.

http://win32.mvps.org/network/nue_nqdi.cpp ("NetUserEnum")
http://win32.mvps.org/network/nugi.cpp ("NetUserGetInfo")

You'll need the 1st API to enumerate all users, then the 2nd one to obtain the home directory, which will be returned in USER_INFO_3::usri3_home_dir:

// compile with:
//            "cl -DUNICODE nugi.cpp" for a Unicode app
//            "cl nugi.cpp" for an MBCS app

// make sure that either both _UNICODE and UNICODE are defined, or none of them is
#if defined( _UNICODE ) && ! defined( UNICODE )
#define UNICODE 1
#endif
#if defined( UNICODE ) && ! defined( _UNICODE )
#define _UNICODE 1
#endif

#include <windows.h>
#include <lm.h>
#include <stdio.h>
#include <time.h>
#include <tchar.h>
#pragma hdrstop
#pragma comment( lib, "netapi32.lib" )



// in Unicode apps, _tprintf() maps to wprintf(), and "%s" refers to
// a Unicode string, while "%S" wants an ANSI string. In MBCS apps,
// "%s" expects an ANSI string, while "%S" wants a Unicode string. We
// could do some creative trickery with macros, but I am lazy, so I'll
// rely on "%hs" and "%ls" instead. Independent of whether printf() or
// wprintf() is ultimately invokes, "%hs" always expects an ANSI string,
// and "%ls" always expects a Unicode string.
// Since Net*() APIs on NT deal in Unicode only, the strings from the
// USER_INFO_3 struct get shown with "%ls" (but note that strings from
// elsewhere are in the ambient character size and use plain "%s").



#define lenof(a) (sizeof(a)/sizeof((a)[0]))



typedef struct {
      DWORD bits;
      const TCHAR *name;
} flag_t;



const TCHAR *getText( DWORD num, flag_t *defs )
{
      static TCHAR s[60];

      for ( ; defs->name != 0; ++ defs )
      {
            if ( defs->bits == num )
                  return defs->name;
      }

      _stprintf( s, _T( "%lu [0x%lx] (unknown)" ), num, num );
      return &s[0];
}



const TCHAR *buildFlags( DWORD bits, flag_t *defs )
{
      static TCHAR s[4096];
      TCHAR *p = &s[0];

      p += _stprintf( p, _T( "0x%lx" ), bits );

      for ( ; defs->name != 0; ++ defs )
      {
            if ( ( defs->bits & bits ) == defs->bits )
            {
                  if ( p != &s[0] )
                  {
                        _tcscpy( p, _T( ", " ) );
                        p += _tcslen( p );
                  }
                  _tcscpy( p, defs->name );
                  p += _tcslen( p );
            }
      }

      return &s[0];
}



int nugi( TCHAR *machine, TCHAR *user )
{
      DWORD rc;
      USER_INFO_3 *buf = 0;
      TCHAR temp[40];
      wchar_t unicodeMachine[UNCLEN + 4], unicodeUser[UNLEN + 2];
      static flag_t privilegeTexts[] =
      {
            { USER_PRIV_GUEST, _T( "USER_PRIV_GUEST" ) },
            { USER_PRIV_USER, _T( "USER_PRIV_USER" ) },
            { USER_PRIV_ADMIN, _T( "USER_PRIV_ADMIN" ) },
            { 0, 0 }
      };
      static flag_t authFlags[] =
      {
            { AF_OP_PRINT, _T( "AF_OP_PRINT" ) },
            { AF_OP_COMM, _T( "AF_OP_COMM" ) },
            { AF_OP_SERVER, _T( "AF_OP_SERVER" ) },
            { AF_OP_ACCOUNTS, _T( "AF_OP_ACCOUNTS" ) },
            { 0, 0 }
      };
      static flag_t acctFlags[] =
      {
            { UF_SCRIPT, _T( "UF_SCRIPT" ) },
            { UF_ACCOUNTDISABLE, _T( "UF_ACCOUNTDISABLE" ) },
            { UF_HOMEDIR_REQUIRED, _T( "UF_HOMEDIR_REQUIRED" ) },
            { UF_PASSWD_NOTREQD, _T( "UF_PASSWD_NOTREQD" ) },
            { UF_PASSWD_CANT_CHANGE, _T( "UF_PASSWD_CANT_CHANGE" ) },
            { UF_LOCKOUT, _T( "UF_LOCKOUT" ) },
            { UF_DONT_EXPIRE_PASSWD, _T( "UF_DONT_EXPIRE_PASSWD" ) },
#ifdef UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED
            { UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED, _T( "UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED" ) },
#endif
#ifdef UF_NOT_DELEGATED
            { UF_NOT_DELEGATED, _T( "UF_NOT_DELEGATED" ) },
#endif
#ifdef UF_SMARTCARD_REQUIRED
            { UF_SMARTCARD_REQUIRED, _T( "UF_SMARTCARD_REQUIRED" ) },
#endif
            { UF_NORMAL_ACCOUNT, _T( "UF_NORMAL_ACCOUNT" ) },
            { UF_TEMP_DUPLICATE_ACCOUNT, _T( "UF_TEMP_DUPLICATE_ACCOUNT" ) },
            { UF_WORKSTATION_TRUST_ACCOUNT, _T( "UF_WORKSTATION_TRUST_ACCOUNT" ) },
            { UF_SERVER_TRUST_ACCOUNT, _T( "UF_SERVER_TRUST_ACCOUNT" ) },
            { UF_INTERDOMAIN_TRUST_ACCOUNT, _T( "UF_INTERDOMAIN_TRUST_ACCOUNT" ) },
            { 0, 0 }
      };

#ifdef UNICODE
      _tcsncpy( unicodeMachine, machine, lenof( unicodeMachine ) );
      _tcsncpy( unicodeUser, user, lenof( unicodeUser ) );
#else
      mbstowcs( unicodeMachine, machine, lenof( unicodeMachine ) );
      mbstowcs( unicodeUser, user, lenof( unicodeUser ) );
#endif
      unicodeMachine[lenof( unicodeMachine ) - 1] = _T( '\0' );
      unicodeUser[lenof( unicodeUser ) - 1] = _T( '\0' );

      _tprintf( _T( "User %s on %s: " ), user, machine );

      rc = NetUserGetInfo( unicodeMachine, unicodeUser, 3, (byte **) &buf );
      if ( rc != 0 )
      {
            _tprintf( _T( "error %lu.\n" ), rc );
            return rc;
      }

      _tprintf( _T( "found.\n" ) );

      _tprintf( _T( "  Name:          %ls\n" ), buf->usri3_name );
      _tprintf( _T( "  Password:      %ls\n" ), buf->usri3_password );
      _tprintf( _T( "  Password age:  %lu days, %02lu:%02lu:%02lu\n" ), buf->usri3_password_age / 86400UL,
            buf->usri3_password_age % 86400UL / 3600UL, buf->usri3_password_age % 3600UL / 60UL,
            buf->usri3_password_age % 60UL );
      _tprintf( _T( "  Privilege:     %s\n" ), getText( buf->usri3_priv, privilegeTexts ) );
      _tprintf( _T( "  Home dir:      %ls\n" ), buf->usri3_home_dir );
      _tprintf( _T( "  Comment:       %ls\n" ), buf->usri3_comment );
      _tprintf( _T( "  Flags:         %s\n" ), buildFlags( buf->usri3_flags, acctFlags ) );
      _tprintf( _T( "  Script path:   %ls\n" ), buf->usri3_script_path );
      _tprintf( _T( "  Auth flags:    %s\n" ), buildFlags( buf->usri3_auth_flags, authFlags ) );
      _tprintf( _T( "  Full name:     %ls\n" ), buf->usri3_full_name );
      _tprintf( _T( "  User comment:  %ls\n" ), buf->usri3_usr_comment );
      _tprintf( _T( "  RAS params:    (not displayed)\n" ) );
      _tprintf( _T( "  Workstations:  %ls\n" ), buf->usri3_workstations );
      _tprintf( _T( "  Last logon:    %s" ), buf->usri3_last_logon == 0? _T( "never\n" ): _tctime( (long *) &buf->usri3_last_logon ) );
      _tprintf( _T( "  Last logoff:   %s" ), buf->usri3_last_logoff == 0? _T( "unknown\n" ): _tctime( (long *) &buf->usri3_last_logoff ) );
      _tprintf( _T( "  Expires:       %s" ), buf->usri3_acct_expires == TIMEQ_FOREVER? _T( "never\n" ): _tctime( (long *) &buf->usri3_acct_expires ) );
      _tprintf( _T( "  Max storage:   %s\n" ), buf->usri3_max_storage == USER_MAXSTORAGE_UNLIMITED? _T( "unlimited" ): _ultot( buf->usri3_max_storage, temp, 10 ) );
      _tprintf( _T( "  Logon hours:   (not displayed)\n" ) );
      _tprintf( _T( "  Bad PW count:  %s\n" ), buf->usri3_bad_pw_count == (DWORD) -1L? _T( "unlimited" ): _ultot( buf->usri3_bad_pw_count, temp, 10 ) );
      _tprintf( _T( "  # of logons:   %s\n" ), buf->usri3_num_logons == (DWORD) -1L? _T( "unknown" ): _ultot( buf->usri3_num_logons, temp, 10 ) );
      _tprintf( _T( "  Logon server:  %ls\n" ), buf->usri3_logon_server );
      _tprintf( _T( "  Country code:  %lu\n" ), buf->usri3_country_code );
      _tprintf( _T( "  Code page:     %lu\n" ), buf->usri3_code_page );
      _tprintf( _T( "  User RID:      %lu\n" ), buf->usri3_user_id );
      _tprintf( _T( "  Pgroup RID:    %lu\n" ), buf->usri3_primary_group_id );
      _tprintf( _T( "  Profile path:  %ls\n" ), buf->usri3_profile );
      _tprintf( _T( "  Home drive:    %ls\n" ), buf->usri3_home_dir_drive );
      _tprintf( _T( "  PW expired:    %s\n" ), buf->usri3_password_expired? _T( "yes" ): _T( "no" ) );
      _tprintf( _T( "\n" ) );

      return 0;
}



#ifdef UNICODE
int wmain( int argc, TCHAR *argv[] )
#else
int main( int argc, TCHAR *argv[] )
#endif
{
      TCHAR *machine = 0;
      int i;

      if ( argc < 2 )
      {
            _tprintf( _T( "usage: nugi [\\\\machine] user [user ...] [[\\\\machine] user [user ...] ...]\n" ) );
            return 1;
      }

      for ( i = 1; i < argc; ++ i )
      {
            if ( argv[i][0] == _T( '\\' ) && argv[i][1] == _T( '\\' ) )
            {
                  machine = argv[i];
                  continue;
            }

            nugi( machine, argv[i] );
      }

      return 0;
}
Avatar of novitiate
novitiate

You can try to use values in registry key
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\DocFolderPaths", here the example of program code, which will display full path to home directories of every user, registered in system :


 HKEY RegKey;
 CHAR     achKey[MAX_PATH];
 char tmp[MAX_PATH] ;

 RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DocFolderPaths",0,KEY_ALL_ACCESS,&RegKey); // opening key
 int err = 0;
 int i = 0;
 DWORD Size;
 int counter = 0;
 Size = MAX_PATH;

while (err==ERROR_SUCCESS || err == ERROR_MORE_DATA) // start to read sub-keys from opened key
{
err = RegEnumValue(RegKey,i,achKey,&Size,NULL,NULL,NULL,NULL); // extract 'i' sub-key
i++;

if (err != ERROR_NO_MORE_ITEMS)
{
 Size = MAX_PATH;
 RegQueryValueEx(RegKey, achKey, NULL, NULL, tmp, &Size) ; // take its value
 tmp[strlen(tmp) - 13] = '\0'; // cut off '\My Documents' substring in extracted value
 MessageBox(0,tmp, "rs[i]",MB_OK) ; // and show full path
 counter++;
}
}

RegCloseKey(RegKey);
I'd say that this Q is answered.
No comment has been added to this question in more than 21 days, so it is now classified as abandoned..
I will leave the following recommendation for this question in the Cleanup topic area:

Split between jkr, B1-66ER

Any objections should be posted here in the next 4 days. After that time, the question will be closed.

wayside
EE Cleanup Volunteer
Tend to object. You can have users without any "DocFolderPaths" (i.e. all that don't have a profile), thus I consider B1-66ER' suggestion error prone here. It's not the 'official' way anyway.
I think that depends on what the OP meant by "all user accounts on Windows machine." I believe in a local enviroment, all accounts created on that machine will have an entry in DocFolderPaths.
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I stand corrected.

Change recommendation to:

Accept: jkr