
This is my first article on CodeProject. So please don't expect too much. ;-)
An old workstation running Windows 2000 acts as a "file server". Users can access shared folders over the network by connecting using a username and password. Unfortunately, in a workgroup environment, there is no built-in way to change the passwords of these local users from a remote machine.
The described problem can be divided into three main parts:
In the MSDN are three corresponding network management functions mentioned. Their usage is well explained, so I won't recite the MSDN.
NetServerEnumNetQueryDisplayInformation (see: How to get a list of users from a server)NetUserChangePasswordBut the simple NetUserChangePassword function prototype should be self-explanatory.
DWORD NetUserChangePassword( LPCWSTR domainname, LPCWSTR username, LPCWSTR oldpassword, LPCWSTR newpassword );
The different strings (e.g., usernames, passwords) are limited to a certain number of characters. It seems that these limitations are a relic from the NT LAN Manager.
| Name | Length |
| Domain/Workgroup | 15 |
| Server | 15 |
| User | 20 |
| Password | 14 |
NetQueryDisplayInformation requires anonymous access to the remote machine. Furthermore, an established NULL session connection (e.g., to $IPC) is required.
The server and the user enumeration are wrapped into several classes.

Iterating through the result list shouldn't be a big deal.
NetObjectEnumerator *noe = new [ NetServerEnumerator(Domain) | NetUserEnumerator(Server) ] ; if(noe->GetError() == ERROR_SUCCESS){ while(noe->HasNext()){ NetObject *no = noe->GetNext(); ... = no->name; // process the current server/user name... } } else ... = NetObjectEnumerator::GetErrorMessage(noe->GetError()); // process the occurred error...
The FormatMessage function maps an error code to a message. For network management errors, the netmsg.dll module is used to look up the specified errors.
CString GetErrorMessage(DWORD dwLastError){
HMODULE hModule = NULL;
DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM;
LPTSTR lpMessageBuffer = NULL;
if((dwLastError >= NERR_BASE) && (dwLastError <= MAX_NERR)){
hModule = LoadLibraryEx(_T("netmsg.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE);
if(hModule != NULL)
dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
}
FormatMessage(
dwFormatFlags,
hModule,
dwLastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMessageBuffer,
0,
NULL);
CString szMessage;
szMessage.Format(_T("%s (%u)"), lpMessageBuffer, dwLastError);
LocalFree(lpMessageBuffer);
if(hModule != NULL)
FreeLibrary(hModule);
return szMessage;
}
Credits go to Chris Maunder for his great HyperLink static control.
The application has not been tested in a domain environment. Any volunteers?
Please feel free to send your feedback to me via email. Bug reports, spelling corrections, opinions, and comments would be much appreciated.
The newest Password Changer version is also available on my website.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||