ID: Q196070
The information in this article applies to:
- Microsoft Windows NT 4.0
- Microsoft Windows 2000
******************************************************************** BETA INFORMATION BETA INFORMATION BETA INFORMATION BETA This article discusses a Beta release of a Microsoft product. The information in this article is provided as-is and is subject to change without notice. No formal product support is available from Microsoft for this Beta product. For information about obtaining support for a Beta release, please see the documentation included with the Beta product files, or check the Web location from which you downloaded the release. BETA INFORMATION BETA INFORMATION BETA INFORMATION BETA ********************************************************************
This article demonstrates how to programmatically cause a user's profile to be created on Windows NT 4.0 without requiring an interactive logon.
By default on Windows NT 4.0, a new user's profile is not created until the user logs on to the machine interactively. An interactive logon occurs when a user logs on to the machine by pressing CTRL+ALT+DEL to gain access through the WinLogon dialog box.
By dynamically linking with and calling some unexposed User Profile APIs in the system library Userenv.dll, it is possible to cause the Windows NT 4.0 to create a new user's profile.
The following User Profile structures and functions are used in the sample code in this article. Although they are not extensively documented in this article, these structures and functions will be fully exposed and documented in Windows 2000. For more information, refer to the preliminary documentation for these APIs which can be found in the latest release of the Platform SDK (MSDN Update, September 1998).
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 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 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 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().
The sample code below can be compiled as a console application for Windows NT 4.0. 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;
}
Additional query words:
Keywords : kbcode kbKernBase kbNTOS kbNTOS400 kbWinOS2000 kbCodeSam
Version : WINNT:4.0,WIN2000
Platform : winnt
Issue type : kbhowto
Last Reviewed: January 7, 1999