How To Programmatically Cause the Creation of a User's Profile

Article translations Article translations
Article ID: 196070 - View products that this article applies to.
Expand all | Collapse all

On This Page

Summary

This article demonstrates how to programmatically cause a user's profile to be created without requiring an interactive logon.

More information

By default, a new user's profile is not created until the user logs on to the computer interactively. An interactive logon occurs when a user logs on to the computer by pressing CTRL+ALT+DEL to gain access through the WinLogon dialog box.

It is possible to programmatically cause a user's profile to be created without requiring an interactive logon by calling the LoadUserProfile() API. In Windows 2000 and Windows XP, this function is exposed within the Platform SDK header files and documented in the MSDN Library. On Windows NT 4.0, the LoadUserProfile() API is not exposed, but it can still be called by dynamically loading the Userenv.dll library and obtaining a pointer to the function.

Calling LoadUserProfile() on Windows NT 4.0

The remainder of this article demonstrates how to work with the User Profile structures and functions on Windows NT 4.0. For complete information on these structures and functions, refer to the Platform SDK documentation in the latest release of the MSDN Library.

The PROFILEINFO Structure

The PROFILEINFO structure provides information about a user profile:
   typedef struct _PROFILEINFO {
       DWORD   dwSize;          // size of structure
       DWORD   dwFlags;         // flags
       LPTSTR  lpUserName;      // user name
       LPTSTR  lpProfilePath;   // roaming profile path
       LPTSTR  lpDefaultPath;   // default user profile path
       LPTSTR  lpServerName;    // validating domain controller name
       LPTSTR  lpPolicyPath;    // Windows NT 4.0-style policy file
       HANDLE  hProfile;        // registry key handle
   } PROFILEINFO, FAR * LPPROFILEINFO;
				
dwSize specifies the size of the structure, in bytes.

dwFlags can be one of the following flags:
PI_NOUI (1) -- Prevents displaying of profile error messages.
PI_APPLYPOLICY (2) -- Applies a Windows NT 4.0-style policy.
lpUserName is a pointer to the name of the user.

lpProfilePath is a pointer to the roaming profile path.

lpDefaultPath is a pointer to the default user profile path.

lpServerName is a pointer to the name of the validating domain controller, in NetBIOS format.

lpPolicyPath is a pointer to the path of the policy file.

hProfile will contain the HKEY_CURRENT_USER registry key handle upon successful return.

The LoadUserProfile() Function

The LoadUserProfile() function loads the specified user's profile. If the profile does not yet exist, the operating system will create it. The caller must have administrative privileges on the computer.
   BOOL LoadUserProfile(
     HANDLE hToken,
     LPPROFILEINFO lpProfileInfo
   );

   hToken is a token for the user. The token must have TOKEN_IMPERSONATE
   access.

   lpProfileInfo is a pointer to a PROFILEINFO structure.
				
If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError().

Upon successful return, the hProfile member of PROFILEINFO is a registry key handle opened to the root of the user's hive. Do not close the hProfile handle. Instead, pass it to the UnloadUserProfile() function.

The UnloadUserProfile() Function

The UnloadUserProfile function unloads a user's profile that was loaded by the LoadUserProfile function. The caller must have administrative privileges on the computer.
   BOOL UnloadUserProfile(
     HANDLE hToken,
     HANDLE hProfile
   );
				
hToken is a token for the user. The token must have TOKEN_IMPERSONATE access.

hProfile is the hProfile member of the PROFILEINFO structure after a successful call to LoadUserProfile().
If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError().

The GetUserProfileDirectory() Function

The GetUserProfileDirectory function returns the path to the root directory of the specified user's profile.
   BOOL GetUserProfileDirectory(
     HANDLE  hToken,
     LPTSTR lpProfileDir,
     LPDWORD lpcchSize
   );
hToken is a token for the user. The token must have TOKEN_IMPERSONATE access.

lpProfilesDir is a pointer to the buffer that receives the path to the specified user's profile directory.

lpcchSize specifies the size of the lpProfilesDir buffer, in bytes.
If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError().

Sample Code

The sample code below can be compiled as a console application for Windows NT 4.0. This same approach will work on Windows 2000 and Windows XP, but it would generally be easier to include the userenv.h header file and link directly with the userenv.lib library. Implicit linking is preferable because it does not require dynamically loading the DLL and retrieving function pointers for the User Profile APIs.

This code demonstrates how to programmatically create a new user account, force a profile to be created for the new user, and retrieve the new profile directory:
   //**********************************************************************
   // 
   //  This program creates a new user account, forces a profile to be
   //  created for the new user, and retrieves the new profile directory
   // 
   //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
   //  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
   //  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
   //  PARTICULAR PURPOSE.
   // 
   //  Copyright (C) 1998 Microsoft Corporation. All rights reserved.
   //  Author: Jonathan Russ (jruss)
   // 
   //**********************************************************************

   // NOTE: This code must be linked with netapi32.lib

   #include <windows.h>
   #include <tchar.h>
   #include <stdio.h>
   #include <lm.h>

   // Declarations based on USERENV.H for Windows 2000 Beta 2
   #define PI_NOUI         0x00000001   // Prevents displaying of messages
   #define PI_APPLYPOLICY  0x00000002   // Apply NT4 style policy

   typedef struct _PROFILEINFO {
      DWORD    dwSize;          // Must be set to sizeof(PROFILEINFO)
      DWORD    dwFlags;         // See flags above
      LPTSTR   lpUserName;      // User name (required)
      LPTSTR   lpProfilePath;   // Roaming profile path
      LPTSTR   lpDefaultPath;   // Default user profile path
      LPTSTR   lpServerName;    // Validating DC name in netbios format
      LPTSTR   lpPolicyPath;    // Path to the NT4 style policy file
      HANDLE   hProfile;        // Registry key handle - filled by function
   } PROFILEINFO, FAR * LPPROFILEINFO;

   // Typedefs for function pointers in USERENV.DLL
   typedef BOOL (STDMETHODCALLTYPE FAR * LPFNLOADUSERPROFILE) (
      HANDLE hToken,
      LPPROFILEINFO lpProfileInfo
   );

   typedef BOOL (STDMETHODCALLTYPE FAR * LPFNUNLOADUSERPROFILE) (
      HANDLE hToken,
      HANDLE hProfile
   );

   typedef BOOL (STDMETHODCALLTYPE FAR * LPFNGETUSERPROFILEDIR) (
      HANDLE hToken,
      LPTSTR lpProfileDir,
      LPDWORD lpcchSize
   );

   HMODULE                 g_hUserEnvLib           = NULL;
   LPFNLOADUSERPROFILE     LoadUserProfile         = NULL;
   LPFNUNLOADUSERPROFILE   UnloadUserProfile       = NULL;
   LPFNGETUSERPROFILEDIR   GetUserProfileDirectory = NULL;


   //**********************************************************************
   // 
   //  FUNCTION:     InitUserEnv - This function dynamically links to
   //                USERENV.DLL and sets up the required function pointers
   // 
   //  PARAMETERS:   none
   // 
   //  RETURN VALUE: TRUE if successful. Otherwise, FALSE.
   // 
   //**********************************************************************

   BOOL InitUserEnv( void ) {

      g_hUserEnvLib = LoadLibrary( _T("userenv.dll") );
      if ( !g_hUserEnvLib ) {
         _tprintf( _T("LoadLibrary(userenv.dll) failed.  Error %d\n"),
              GetLastError() );
         return FALSE;
      }

   #ifdef UNICODE
      LoadUserProfile =
            (LPFNLOADUSERPROFILE) GetProcAddress( g_hUserEnvLib,
            "LoadUserProfileW" );
   #else
      LoadUserProfile =
            (LPFNLOADUSERPROFILE) GetProcAddress( g_hUserEnvLib,
            "LoadUserProfileA" );
   #endif

      if (!LoadUserProfile) {
         _tprintf( _T("GetProcAddress(%s) failed.  Error %d\n"),
               "LoadUserProfile", GetLastError() );
         return FALSE;
      }

      UnloadUserProfile =
            (LPFNUNLOADUSERPROFILE) GetProcAddress( g_hUserEnvLib,
            "UnloadUserProfile" );

      if (!UnloadUserProfile) {
         _tprintf( _T("GetProcAddress(%s) failed.  Error %d\n"),
               "UnloadUserProfile", GetLastError() );
         return FALSE;
      }

   #ifdef UNICODE
      GetUserProfileDirectory =
            (LPFNGETUSERPROFILEDIR) GetProcAddress( g_hUserEnvLib,
            "GetUserProfileDirectoryW" );
   #else
      GetUserProfileDirectory =
            (LPFNGETUSERPROFILEDIR) GetProcAddress( g_hUserEnvLib,
            "GetUserProfileDirectoryA" );
   #endif

      if (!GetUserProfileDirectory) {
         _tprintf( _T("GetProcAddress(%s) failed.  Error %d\n"),
               "GetUserProfileDirectory", GetLastError() );
         return FALSE;
      }

      return TRUE;
   }


   //**********************************************************************
   // 
   //  FUNCTION:     _tmain - This is the entry point for the program.
   // 
   //  PARAMETERS:   argc - the number of command-line arguments
   //                argv - an array of null-terminated strings specifying
   //                       the command-line arguments
   //                envp - an array of null-terminated strings specifying
   //                       the environment strings
   // 
   //  RETURN VALUE: Zero if successful. Otherwise, non-zero.
   // 
   //**********************************************************************

   #ifdef __cplusplus
      extern "C"
   #endif

   #ifdef UNICODE
      int _cdecl
   #else
      int
   #endif

   _tmain(int argc, _TCHAR **argv, _TCHAR **envp) {

      USER_INFO_1   ui1;
      DWORD         dwError;
      HANDLE        hToken;
      PROFILEINFO   pi;
      TCHAR         szProfilePath[1024];
      DWORD         cchPath = 1024;
      WCHAR         szUserName[20];
      WCHAR         szPassword[20];

      // Check for the required command-line arguments
      if (argc < 2) {
         _tprintf( _T("Usage: AddUser <user> [password]\n") );
         return -1;
      }

      // Set USERENV.DLL function pointers
      if ( !InitUserEnv() ) {
         _tprintf( _T("Failed to set USERENV.DLL function pointers.\n") );
         return -1;
      }

      // Create local copies of the user name and password
      #ifdef UNICODE

      _tcscpy( szUserName, argv[1] );
      if ( argc == 2 ) {
         _tcscpy( szPassword, szUserName );
      } else {
         _tcscpy( szPassword, argv[2] );
      }

      #else
      {
         int n;

         n = MultiByteToWideChar(0, 0, argv[1], -1, szUserName, 20);
         if (n == 0)
         {
            _tprintf( _T("Failed to convert username to unicode\n"));
            return -1;
         }

         if ( argc == 2 ) {
            n = MultiByteToWideChar(0, 0, argv[1], -1, szPassword, 20);
         } else {
            n = MultiByteToWideChar(0, 0, argv[2], -1, szPassword, 20);
         }
         if (n == 0)
         {
            _tprintf( _T("Failed to convert password to unicode\n"));
            return -1;
         }
      }
      #endif

      // Set up the USER_INFO_1 structure that will be used to create the
      // new user account
      ZeroMemory( &ui1, sizeof(ui1) );
      ui1.usri1_name = szUserName;
      ui1.usri1_password = szPassword;
      ui1.usri1_priv = USER_PRIV_USER;
      ui1.usri1_flags = UF_NORMAL_ACCOUNT | UF_SCRIPT;

      // Create the new user account
      dwError = NetUserAdd(
            NULL,            // target computer name
            1,               // info level
            (LPBYTE) &ui1,   // address of user info structure
            NULL );          // index to invalid parameter
      if ( dwError != NERR_Success ) {
         _tprintf( _T("NetUserAdd() failed.  Error %d\n"), dwError );
         dwError = ERROR_ACCESS_DENIED;
         return -1;
      }

      // Do a network logon because most systems do not grant new users
      // the right to logon interactively (SE_INTERACTIVE_LOGON_NAME)
      // but they do grant the right to do a network logon
      // (SE_NETWORK_LOGON_NAME). A network logon has the added advantage
      // of being quicker.

      // NOTE: To call LogonUser(), the current user must have the
      // SE_TCB_NAME privilege
      if ( !LogonUser(
            argv[1],                        // user name
            _T("."),                        // domain or server
            (argc == 2) ? argv[1]:argv[2],  // password
            LOGON32_LOGON_NETWORK,          // type of logon operation
            LOGON32_PROVIDER_DEFAULT,       // logon provider
            &hToken ) ) {                   // pointer to token handle
         _tprintf( _T("LogonUser() failed.  Error %d\n"), GetLastError() );
         return -1;
      }

      // Set up the PROFILEINFO structure that will be used to load the
      // new user's profile
      ZeroMemory( &pi, sizeof(pi) );
      pi.dwSize = sizeof(pi);

      #ifdef UNICODE
      pi.lpUserName = szUserName;
      #else
      pi.lpUserName = argv[1];
      #endif

      pi.dwFlags = PI_NOUI;

      // Load the profile. Since it doesn't exist, it will be created
      if ( !LoadUserProfile(
            hToken,        // token for the user
            &pi ) ) {      // pointer to PROFILEINFO structure
         _tprintf( _T("LoadUserProfile() failed.  Error %d\n"),
               GetLastError() );
         return -1;
      }

      // Unload the profile when it is no longer needed
      if ( !UnloadUserProfile(
            hToken,              // token for the user
            pi.hProfile ) ) {    // registry key handle
         _tprintf( _T("UnloadUserProfile() failed.  Error %d\n"),
               GetLastError() );
         return -1;
      }

      // Retrieve the new user's profile directory
      if ( !GetUserProfileDirectory( hToken, szProfilePath, &cchPath ) ) {
         _tprintf( _T("GetProfilePath() failed.  Error %d\n"),
               GetLastError() );
         return -1;
      }

      // Display the new user's profile directory
      _tprintf( _T("The new user's profile path is %s\n"), szProfilePath );

      // Release USERENV.DLL
      if ( g_hUserEnvLib ) {
         FreeLibrary( g_hUserEnvLib );
      }

      return 0;
   }
				

Properties

Article ID: 196070 - Last Review: June 22, 2014 - Revision: 6.0
Applies to
  • Microsoft Win32 Application Programming Interface
Keywords: 
kbcode kbhowto kbkernbase KB196070

Give Feedback

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com